volley源码解析
来源:互联网 发布:新华电脑软件学校 编辑:程序博客网 时间:2024/06/10 01:47
总结一下Volley:
功能方面:
基于HttpURLConnection HttpClient;封装了UIL图片加载框架,支持图片加载;网络请求的排序,优先级处理;添加了网路缓存;
支持多级别取消网络请求;Activity和生命周期的联动(Activity结束时取消所有的网络请求)
可扩展性好支持HttpURLConnection HttpClient以及OKHttp
使用于数据量小但网络请求频繁的场景
缺点:不适合大数据量的网络请求
下面结合源码分析一下,先上官网的原理图
首先通过Volley构建出请求队列
public static RequestQueue newRequestQueue(Context context, BaseHttpStack stack) { BasicNetwork network; if (stack == null) { if (Build.VERSION.SDK_INT >= 9) { network = new BasicNetwork(new HurlStack()); } else { // Prior to Gingerbread, HttpUrlConnection was unreliable. // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html // At some point in the future we'll move our minSdkVersion past Froyo and can // delete this fallback (along with all Apache HTTP code). String userAgent = "volley/0"; try { String packageName = context.getPackageName(); PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); userAgent = packageName + "/" + info.versionCode; } catch (NameNotFoundException e) { } network = new BasicNetwork( new HttpClientStack(AndroidHttpClient.newInstance(userAgent))); } } else { network = new BasicNetwork(stack); } return newRequestQueue(context, network); }在创建请求队列时会先去创建一个Httpstack,这里从源码可以看到9之前采用的是HurlStack 继续查看HurlStack的源码发现在执行请求时会调用
openConnection(parsedUrl, request);获取得到网络连接在接下去发现调用的createConnection(url);这个方法,在此方法中我们发现最终调用的是(HttpURLConnection) url.openConnection();因此Android 9 之前Volley底层采用的是HttpURLConnection的网络请求方式、而9以后默认的采用的是HttpClientStack而点进去查看发现其采用的是HttpClient的网络请求。
public HttpResponse executeRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { String url = request.getUrl(); HashMap<String, String> map = new HashMap<>(); map.putAll(request.getHeaders()); map.putAll(additionalHeaders); if (mUrlRewriter != null) { String rewritten = mUrlRewriter.rewriteUrl(url); if (rewritten == null) { throw new IOException("URL blocked by rewriter: " + url); } url = rewritten; } URL parsedUrl = new URL(url); HttpURLConnection connection = openConnection(parsedUrl, request); for (String headerName : map.keySet()) { connection.addRequestProperty(headerName, map.get(headerName)); } setConnectionParametersForRequest(connection, request); // Initialize HttpResponse with data from the HttpURLConnection. int responseCode = connection.getResponseCode(); if (responseCode == -1) { // -1 is returned by getResponseCode() if the response code could not be retrieved. // Signal to the caller that something was wrong with the connection. throw new IOException("Could not retrieve response code from HttpUrlConnection."); } if (!hasResponseBody(request.getMethod(), responseCode)) { return new HttpResponse(responseCode, convertHeaders(connection.getHeaderFields())); } return new HttpResponse(responseCode, convertHeaders(connection.getHeaderFields()), connection.getContentLength(), inputStreamFromConnection(connection)); }
private HttpURLConnection openConnection(URL url, Request<?> request) throws IOException { HttpURLConnection connection = createConnection(url); int timeoutMs = request.getTimeoutMs(); connection.setConnectTimeout(timeoutMs); connection.setReadTimeout(timeoutMs); connection.setUseCaches(false); connection.setDoInput(true); // use caller-provided custom SslSocketFactory, if any, for HTTPS if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) { ((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory); } return connection; }
protected HttpURLConnection createConnection(URL url) throws IOException { HttpURLConnection connection = (HttpURLConnection) url.openConnection(); // Workaround for the M release HttpURLConnection not observing the // HttpURLConnection.setFollowRedirects() property. // https://code.google.com/p/android/issues/detail?id=194495 connection.setInstanceFollowRedirects(HttpURLConnection.getFollowRedirects()); return connection; }
而同时Volley也是支持okhttp作为底层网络请求的。这就需要自己构建OKHttpStack
方式一: 可以参照HurlStack的方式使用OkHttpStack extends HurlStac在重写
首先build.gradle中添加okhttp与okhttp-urlconnection的支持
compile 'com.squareup.okhttp3:okhttp:3.2.0' compile 'com.squareup.okhttp3:okhttp-urlconnection:3.2.0'createConnection方法
protected HttpURLConnection createConnection(URL url) throws IOException { OkUrlFactory okUrlFactory = new OkUrlFactory(okHttpClient); return okUrlFactory.open(url); }
方法二
在eclipse中添加okhttp.jar支持此外定义okhttp重写performRequest方法
import java.io.IOException;import java.util.Map;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.ProtocolVersion;import org.apache.http.entity.BasicHttpEntity;import org.apache.http.message.BasicHeader;import org.apache.http.message.BasicHttpResponse;import org.apache.http.message.BasicStatusLine;import com.yulong.mobile.netroid.Request;import com.yulong.mobile.netroid.error.AuthFailureError;import android.annotation.SuppressLint;import android.content.Context;import android.os.Build;import android.webkit.WebSettings;import okhttp3.Call;import okhttp3.Headers;import okhttp3.MediaType;import okhttp3.OkHttpClient;import okhttp3.Protocol;import okhttp3.RequestBody;import okhttp3.Response;import okhttp3.ResponseBody;public class OkHttpStack implements HttpStack { private final OkHttpClient mOkHttpClient; private Context mContext; public OkHttpStack(Context context,OkHttpClient okHttpClient) { if (okHttpClient == null) { throw new IllegalArgumentException("OkHttpClient can't be null"); } this.mContext = context; mOkHttpClient = okHttpClient; } @SuppressLint("NewApi")private String getUserAgent() { String userAgent = ""; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { try { userAgent = WebSettings.getDefaultUserAgent(mContext); } catch (Exception e) { userAgent = System.getProperty("http.agent"); } } else { userAgent = System.getProperty("http.agent"); } StringBuffer sb = new StringBuffer(); for (int i = 0, length = userAgent.length(); i < length; i++) { char c = userAgent.charAt(i); if (c <= '\u001f' || c >= '\u007f') { sb.append(String.format("\\u%04x", (int) c)); } else { sb.append(c); } } return sb.toString(); } @Overridepublic HttpResponse performRequest(Request<?> request) throws IOException, AuthFailureError { OkHttpClient client = mOkHttpClient; int timeoutMs = request.getTimeoutMs(); okhttp3.Request.Builder builder = new okhttp3.Request.Builder(); builder.url(request.getUrl()); Map<String, String> headers = request.getHeaders(); for (String name : headers.keySet()) { builder.addHeader(name, headers.get(name)); } builder.removeHeader("User-Agent").addHeader("User-Agent",getUserAgent()).build(); setConnectionParametersForRequest(builder, request); okhttp3.Request okRequest = builder.build(); okhttp3.Call call = client.newCall(okRequest); okhttp3.Response okresponse = call.execute(); BasicStatusLine responseStatus = new BasicStatusLine( parseProtocol(okresponse.protocol()), okresponse.code(), okresponse.message() ); BasicHttpResponse response = new BasicHttpResponse(responseStatus); response.setEntity(entityFromOkHttpResponse(okresponse)); Headers responseHeaders = okresponse.headers(); int size = responseHeaders.size(); String name = null; String value = null; for (int i = 0; i < size; i++) { name = responseHeaders.name(i); if (name != null) { response.addHeader(new BasicHeader(name, value)); } } return response;}private static HttpEntity entityFromOkHttpResponse(Response r) throws IOException { BasicHttpEntity entity = new BasicHttpEntity(); ResponseBody body = r.body(); entity.setContent(body.byteStream()); entity.setContentLength(body.contentLength()); entity.setContentEncoding(r.header("Content-Encoding")); if (body.contentType() != null) { entity.setContentType(body.contentType().type()); } return entity; } static void setConnectionParametersForRequest(okhttp3.Request.Builder builder, Request<?> request) throws IOException, AuthFailureError { switch (request.getMethod()) { case Request.Method.GET: builder.get(); break; case Request.Method.DELETE: builder.delete(); break; case Request.Method.POST: builder.post(createRequestBody(request)); break; case Request.Method.PUT: builder.put(createRequestBody(request)); break; case Request.Method.HEAD: builder.head(); break; case Request.Method.OPTIONS: builder.method("OPTIONS", null); break; case Request.Method.TRACE: builder.method("TRACE", null); break; case Request.Method.PATCH: builder.patch(createRequestBody(request)); break; default: throw new IllegalStateException("Unknown method type."); } } private static RequestBody createRequestBody(Request r) throws AuthFailureError { final byte[] body = r.getBody(); if (body == null) return null; return RequestBody.create(MediaType.parse(r.getBodyContentType()), body); } private static ProtocolVersion parseProtocol(final Protocol p) { switch (p) { case HTTP_1_0: return new ProtocolVersion("HTTP", 1, 0); case HTTP_1_1: return new ProtocolVersion("HTTP", 1, 1); case SPDY_3: return new ProtocolVersion("SPDY", 3, 1); case HTTP_2: return new ProtocolVersion("HTTP", 2, 0); } throw new IllegalAccessError("Unkwown protocol"); } }
回到正题我们继续跟进去查看newRequestQueue(context, network)的源代码,发现构建RequestQueue之后会将其start()启动而在start()方法当中
public void start() { stop(); // Make sure any currently running dispatchers are stopped. // Create the cache dispatcher and start it. mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); mCacheDispatcher.start(); // Create network dispatchers (and corresponding threads) up to the pool size. for (int i = 0; i < mDispatchers.length; i++) { NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery); mDispatchers[i] = networkDispatcher; networkDispatcher.start(); } }
volley构建了CacheDispatcher实例(CacheDispatcher extends Thread)然后调用了start方法,随后在for循环当中构建了NetworkDispatcher实例并也调用了start方法.默认情况下for循环会执行四次,这样也就是说后天会有五条线程在执行等待网络请求
创建RequestQueue之后我们需要构建出Request然后将其add添加到RequestQueue当中
public <T> Request<T> add(Request<T> request) { // Tag the request as belonging to this queue and add it to the set of current requests. request.setRequestQueue(this); synchronized (mCurrentRequests) { mCurrentRequests.add(request); } // Process requests in the order they are added. request.setSequence(getSequenceNumber()); request.addMarker("add-to-queue"); // If the request is uncacheable, skip the cache queue and go straight to the network. if (!request.shouldCache()) { mNetworkQueue.add(request); return request; } mCacheQueue.add(request); return request; }
前面忘记交代RequestQueue当中会有两条优先级队列
PriorityBlockingQueue<Request<?>> mCacheQueue =new PriorityBlockingQueue<>();
缓存队列PriorityBlockingQueue<Request<?>> mNetworkQueue = new PriorityBlockingQueue<>(); 网络请求队列分别用来管理各自当中的request
从上面的add()当中的源码可知.volley会按照是否需要缓存调到多对应的队列当中,分别出队列交给CacheDispatcher实例以及NetworkDispatcher实例处理请求。
接下来先看看CacheDispatcher的处理方式其run方法
@Override public void run() { if (DEBUG) VolleyLog.v("start new dispatcher"); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // Make a blocking call to initialize the cache. mCache.initialize(); while (true) { try { // Get a request from the cache triage queue, blocking until // at least one is available. final Request<?> request = mCacheQueue.take(); request.addMarker("cache-queue-take"); // If the request has been canceled, don't bother dispatching it. if (request.isCanceled()) { request.finish("cache-discard-canceled"); continue; } // Attempt to retrieve this item from cache. Cache.Entry entry = mCache.get(request.getCacheKey()); if (entry == null) { request.addMarker("cache-miss"); // Cache miss; send off to the network dispatcher. if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) { mNetworkQueue.put(request); } continue; } // If it is completely expired, just send it to the network. if (entry.isExpired()) { request.addMarker("cache-hit-expired"); request.setCacheEntry(entry); if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) { mNetworkQueue.put(request); } continue; } // We have a cache hit; parse its data for delivery back to the request. request.addMarker("cache-hit"); Response<?> response = request.parseNetworkResponse( new NetworkResponse(entry.data, entry.responseHeaders)); request.addMarker("cache-hit-parsed"); if (!entry.refreshNeeded()) { // Completely unexpired cache hit. Just deliver the response. mDelivery.postResponse(request, response); } else { // Soft-expired cache hit. We can deliver the cached response, // but we need to also send the request to the network for // refreshing. request.addMarker("cache-hit-refresh-needed"); request.setCacheEntry(entry); // Mark the response as intermediate. response.intermediate = true; if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) { // Post the intermediate response back to the user and have // the delivery then forward the request along to the network. mDelivery.postResponse(request, response, new Runnable() { @Override public void run() { try { mNetworkQueue.put(request); } catch (InterruptedException e) { // Restore the interrupted status Thread.currentThread().interrupt(); } } }); } else { // request has been added to list of waiting requests // to receive the network response from the first request once it returns. mDelivery.postResponse(request, response); } } } catch (InterruptedException e) { // We may have been interrupted because it was time to quit. if (mQuit) { return; } } } }
可以看到缓存线程当中有一个while循环一直在处理request请求,先会去cache当中获取是否存在,并查看是否数据是否已经过期,否则重新添加到networkQueue(
这个NetworkQueue就是在RequestQueue start()执行构建CacheDispatcher时创建并传入的)如果存在并数据有效调用
mDelivery.postResponse(request, response);方法将数据返回mDelivery即在RequestQueue创建时构建的new ExecutorDelivery(new Handler(Looper.getMainLooper()))
查看ExecutorDelivery 的postResponse方法
ExecutorDeliveryd
public ExecutorDelivery(final Handler handler) { // Make an Executor that just wraps the handler. mResponsePoster = new Executor() { @Override public void execute(Runnable command) { handler.post(command); } };}
查看ExecutorDelivery 的postResponse方法
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) { request.markDelivered(); request.addMarker("post-response"); mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable)); } private class ResponseDeliveryRunnable implements Runnable { private final Request mRequest; private final Response mResponse; private final Runnable mRunnable; public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) { mRequest = request; mResponse = response; mRunnable = runnable; } @SuppressWarnings("unchecked") @Override public void run() { // If this request has canceled, finish it and don't deliver. if (mRequest.isCanceled()) { mRequest.finish("canceled-at-delivery"); return; } // Deliver a normal response or error, depending. if (mResponse.isSuccess()) { mRequest.deliverResponse(mResponse.result); } else { mRequest.deliverError(mResponse.error); } // If this is an intermediate response, add a marker, otherwise we're done // and the request can be finished. if (mResponse.intermediate) { mRequest.addMarker("intermediate-response"); } else { mRequest.finish("done"); } // If we have been provided a post-delivery runnable, run it. if (mRunnable != null) { mRunnable.run(); } } }
从以上可以看出,最后调用handle.post方法将结果返回到主线程 通过mRequest.deliverResponse(mResponse.result);回调到了request的方法 而request的抽象方法deliverResponse在StringRequest等都会有实现
可以看到最终还是通过Handler.post的方式回到而来主线程,而Handler则是在RequestQueue构造过程中new出Handler传递给ExecutorDelivery的。看一下RequestQueue当中
的构造方法
public RequestQueue(Cache cache, Network network, int threadPoolSize) { this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper()))); }
new Handler(Loop.getMainLooper())RequestQueue实例创建时候还在主线程。从这这种就构建好ExecutorDelviery实例
CacheDispatcher中会用传进取得Cache实现类DiskBasedCache来实现缓存
DiskBasedCache中有
private final Map<String, CacheHeader> mEntries = new LinkedHashMap<String, CacheHeader>(16, .75f, true);
作为缓存数据同时会将data数据写入磁盘当中
public synchronized void put(String key, Entry entry) { pruneIfNeeded(entry.data.length); File file = getFileForKey(key); try { BufferedOutputStream fos = new BufferedOutputStream(createOutputStream(file)); CacheHeader e = new CacheHeader(key, entry); boolean success = e.writeHeader(fos); if (!success) { fos.close(); VolleyLog.d("Failed to write header for %s", file.getAbsolutePath()); throw new IOException(); } fos.write(entry.data); fos.close(); putEntry(key, e); return; } catch (IOException e) { } boolean deleted = file.delete(); if (!deleted) { VolleyLog.d("Could not clean up file %s", file.getAbsolutePath()); } }
@Override protected void deliverResponse(String response) { if (mListener != null) { mListener.onResponse(response); } }最后真正会掉到了request传来的listener
这个具体的deliverResponse()方法当然最后可以自己具体的做实现,同样错误时一样的道理
同理在查看NetworkDispatch
@Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); while (true) { long startTimeMs = SystemClock.elapsedRealtime(); Request<?> request; try { // Take a request from the queue. request = mQueue.take(); } catch (InterruptedException e) { // We may have been interrupted because it was time to quit. if (mQuit) { return; } continue; } try { request.addMarker("network-queue-take"); // If the request was cancelled already, do not perform the // network request. if (request.isCanceled()) { request.finish("network-discard-cancelled"); continue; } addTrafficStatsTag(request); // Perform the network request. NetworkResponse networkResponse = mNetwork.performRequest(request); request.addMarker("network-http-complete"); // If the server returned 304 AND we delivered a response already, // we're done -- don't deliver a second identical response. if (networkResponse.notModified && request.hasHadResponseDelivered()) { request.finish("not-modified"); continue; } // Parse the response here on the worker thread. Response<?> response = request.parseNetworkResponse(networkResponse); request.addMarker("network-parse-complete"); // Write to cache if applicable. // TODO: Only update cache metadata instead of entire record for 304s. if (request.shouldCache() && response.cacheEntry != null) { mCache.put(request.getCacheKey(), response.cacheEntry); request.addMarker("network-cache-written"); } // Post the response back. request.markDelivered(); mDelivery.postResponse(request, response); } catch (VolleyError volleyError) { volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); parseAndDeliverNetworkError(request, volleyError); } catch (Exception e) { VolleyLog.e(e, "Unhandled exception %s", e.toString()); VolleyError volleyError = new VolleyError(e); volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); mDelivery.postError(request, volleyError); } } }
调用BasicNetwork中的performRequest执行网络请求可以看到
responseContents = inputStreamToBytes(inputStream, httpResponse.getContentLength());Volley使用byte[]接收网络返回的数据的。所以不建议有大数据量返回时
使用volley作为网络请求
@Override public NetworkResponse performRequest(Request<?> request) throws VolleyError { long requestStart = SystemClock.elapsedRealtime(); while (true) { HttpResponse httpResponse = null; byte[] responseContents = null; List<Header> responseHeaders = Collections.emptyList(); try { // Gather headers. Map<String, String> additionalRequestHeaders = getCacheHeaders(request.getCacheEntry()); httpResponse = mBaseHttpStack.executeRequest(request, additionalRequestHeaders); int statusCode = httpResponse.getStatusCode(); responseHeaders = httpResponse.getHeaders(); // Handle cache validation. if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) { Entry entry = request.getCacheEntry(); if (entry == null) { return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED, null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); } // Combine cached and response headers so the response will be complete. List<Header> combinedHeaders = combineHeaders(responseHeaders, entry); return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED, entry.data, combinedHeaders, true, SystemClock.elapsedRealtime() - requestStart); } // Some responses such as 204s do not have content. We must check. InputStream inputStream = httpResponse.getContent(); if (inputStream != null) { responseContents = inputStreamToBytes(inputStream, httpResponse.getContentLength()); } else { // Add 0 byte response as a way of honestly representing a // no-content request. responseContents = new byte[0]; } // if the request is slow, log it. long requestLifetime = SystemClock.elapsedRealtime() - requestStart; logSlowRequests(requestLifetime, request, responseContents, statusCode); if (statusCode < 200 || statusCode > 299) { throw new IOException(); } return new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart); } catch (SocketTimeoutException e) { attemptRetryOnException("socket", request, new TimeoutError()); } catch (MalformedURLException e) { throw new RuntimeException("Bad URL " + request.getUrl(), e); } catch (IOException e) { int statusCode; if (httpResponse != null) { statusCode = httpResponse.getStatusCode(); } else { throw new NoConnectionError(e); } VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl()); NetworkResponse networkResponse; if (responseContents != null) { networkResponse = new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart); if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED || statusCode == HttpURLConnection.HTTP_FORBIDDEN) { attemptRetryOnException("auth", request, new AuthFailureError(networkResponse)); } else if (statusCode >= 400 && statusCode <= 499) { // Don't retry other client errors. throw new ClientError(networkResponse); } else if (statusCode >= 500 && statusCode <= 599) { if (request.shouldRetryServerErrors()) { attemptRetryOnException("server", request, new ServerError(networkResponse)); } else { throw new ServerError(networkResponse); } } else { // 3xx? No reason to retry. throw new ServerError(networkResponse); } } else { attemptRetryOnException("network", request, new NetworkError()); } } } }
mBaseHttpStack.executeRequest(request, additionalRequestHeaders);
即调用的是刚开始RequestQueue构建时传入的HttpStack实例的executeRequest方法。所以在HttpStack的构建当中可以做出可以合适的选择,目前来说volley是支持
HttpURLConnection,HttpClient以及OkHttp的
从源码看Volley还对网络错误做了相应的处理
多级别取消:
request.cancel();以及requestQueue.cancalAll()在BasicNetwork的performRequest方法中有做request是否取消的判断
if (request.isCanceled()) { request.finish("network-discard-cancelled"); request.notifyListenerResponseNotUsable(); continue; }
同样requestQueue当中有对请求队列当中取消请求的方法
/** * Cancels all requests in this queue with the given tag. Tag must be non-null * and equality is by identity. */ public void cancelAll(final Object tag) { if (tag == null) { throw new IllegalArgumentException("Cannot cancelAll with a null tag"); } cancelAll(new RequestFilter() { @Override public boolean apply(Request<?> request) { return request.getTag() == tag; } }); }
volley与activity的联动在activity的onStop方法当中添加如下代码即可
@Override protected void onStop() { super.onStop(); //通过Tag标签取消请求队列中对应的全部请求 MyApplication.getHttpQueue().cancelAll("abcPost"); }
volley配置重新请求retry
stringRequest.setRetryPolicy(new DefaultRetryPolicy(timeout * 1000, retrytime, 0.0f));
具体查看volley重试
Volley的缓存实现
Request当中有对应的mShouldCache用来决定是否需要缓存
而在向RequestQueue当中添加request的时候 会按照request的mShouldCache的值来判断是加入到cacheQueue还是networkQueue
public <T> Request<T> add(Request<T> request) { // Tag the request as belonging to this queue and add it to the set of current requests. request.setRequestQueue(this); synchronized (mCurrentRequests) { mCurrentRequests.add(request); } // Process requests in the order they are added. request.setSequence(getSequenceNumber()); request.addMarker("add-to-queue"); // If the request is uncacheable, skip the cache queue and go straight to the network. if (!request.shouldCache()) { mNetworkQueue.add(request); return request; } mCacheQueue.add(request); return request; }
而上面知道了 start的时候会调用对应的Dispather执行对应的操作
Volley的多级别退出以及与Fragment、Activity联动
在RqeustQueue当中
public void cancelAll(RequestFilter filter) { synchronized (mCurrentRequests) { for (Request<?> request : mCurrentRequests) { if (filter.apply(request)) { request.cancel(); } } } }
在request当中
public void cancel() { mCanceled = true; }最后在NetworkDiapatcher中
if (request.isCanceled()) { request.finish("network-discard-cancelled"); request.notifyListenerResponseNotUsable(); continue; }
而在CacheDispatcher当中if (request.isCanceled()) { request.finish("cache-discard-canceled"); continue; }
所以可以在Activity或者Fragment当中的onDestroy当中调用cancel方法即可
volley重请求实现RetryPolicy 然后通过stringRequest.setRetryPolicy(。。。);设置
Volley顺序请求
request当中有sequence字段为什么说Volley适合频繁但是数据量小的网络请求而不适合大数据量的网络请求
在BasicNetWork的performRequest当中会发现byte[] responseContents = null;...responseContents = inputStreamToBytes(inputStream, httpResponse.getContentLength());这就是说volley在做网络请求时使用的是byte[]数组进行的接收而不是使用的stream,这样当遇到大文件时容易导致内存溢出接下来对应的流转化成byte[]protected final ByteArrayPool mPool;http://blog.csdn.net/ss1168805219/article/details/52039444private byte[] inputStreamToBytes(InputStream in, int contentLength) throws IOException, ServerError { PoolingByteArrayOutputStream bytes = new PoolingByteArrayOutputStream(mPool, contentLength); byte[] buffer = null; try { if (in == null) { throw new ServerError(); } buffer = mPool.getBuf(1024); int count; while ((count = in.read(buffer)) != -1) { bytes.write(buffer, 0, count); } return bytes.toByteArray(); } finally { try { // Close the InputStream and release the resources by "consuming the content". if (in != null) { in.close(); } } catch (IOException e) { // This can happen if there was an exception above that left the stream in // an invalid state. VolleyLog.v("Error occurred when closing InputStream"); } mPool.returnBuf(buffer); bytes.close(); } }ByteArrayPool 因为ByteArrayPool的存在而适合网络请求得到数据,就需要在内存开辟一个控件来存储数据;当网络请求频繁的时候,我们先要在堆中开辟存储空间,显示以后再合适的情况下有GC回收,这样频繁的时候GC的工作量会很大,然后导致客户端有压力,于是有了ByteArrayPool字节数据缓存池ByteArrayPool会有mPool.getBuf(1024);以及mPool.returnBuf(buffer);来完成从缓存区取和还的过程最后理一下Volley的整个执行过程 NetworkDiapatcher 以及CacheDiapatcher两个线程进行网络请求的处理,NetworkDispatcher调用BasicNetwork(implements Network)的performRequest方法这之中调用httpStack的performRequst返回响应数据经BasicNetwork处理(这种中又byte[]接收ByteArrayPool加大了内存使用效率)请求状态码并返回对应的响应数据给NetworkDispatcher。之后NetworkDispatcher调用Request的parseNetworkResponse返回Response。最后通过ExecutorDelivery的postResponse由Handler的post回到主线程。调用request的deliverResponse方法调用Listener来进行回调。走完整个流程与NetworkDispatcher不同的是CacheDispatcher仅仅只是有缓存直接返回Response画了一个草图
- 【Volley】Volley源码解析
- volley源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- 选项卡 模板
- 枚举--JAVA
- GitHub 万星推荐:黑客成长技术清单
- Ubuntu16.04开机蓝屏问题解决
- 火狐浏览器a标签出现虚线的解决方法
- volley源码解析
- Hibernate缓存
- 文件上传漏洞
- 记一次阿里复试
- 11 种编程语言的常用按键
- BZOJ 1975 [Sdoi2010]魔法猪学院
- 如何分割字符串
- thinkPHP3.1.2多表事务,批量插入数据, 详解and实例
- (六)Linux内核分析