Volley源码流程解析
2016-09-03 16:49
369 查看
Volley的使用十分简单,我们从网络请求开始说起,你只需要做4件事。
1、新建RequestQueue
2、新建Request对象及数据回调
3、把Request对象添加进RequestQueue
4、RequestQueue.Start();
如果你已经有了一个RequestQueue,直接做2、3步即可
这样就完成了一次网络请求并处理获取的数据
让我们来看看内部是怎么实现的
首先是获取请求队列RequestQueue
一般来说我们会使用Volley.newRequestQueue(context);
我们来看这一段:
这一段里面根据实际手机的Android版本创建了一个HttpStack,HttpUrlConnection在Android2.2以前有个bug,调用 close() 函数会影响连接池,导致连接复用失效,所以在 Froyo 之前使用 HttpURLConnection 需要关闭 keepAlive,详细的可以看上面注释里给出的链接。谷歌认为HttpUrlConnection更适合安卓,有兴趣可以看看这个:http://android-developers.blogspot.com/2011/09/androids-http-clients.html
然后创建一个network对象,并用network和stack对象作为参数生成RequestQueue返回给我们。
由于我们没有指定线程池的大小,默认会生成1个NetWorkDsispatcher(extendsThread
)数组,这个数组大小为4,同时文件缓存被指定为5MB大小。
这里Volley选择自己来管理线程池,而不是使用java提供的ThreadPool。
现在让我们来看看Request对象。
在Volley里面有多种Request,StringRequest,JsonObjectRequest等,里面的处理逻辑只在parseNetworkResponse这个方法中有较大差别,在这里实现数据类型转换,也就是说,如果你有需要,也可以自己继承Request来写一个自己的转换,例如XML解析什么的。
在上面StringRequest对象生成中,我们调用了:
这里额外指定了以GET方法进行网络请求
然后把参数交由父类处理,自己处理成功回调mListener
那我们来看看父类
这里生成了一个唯一ID,并且设置了一个网络请求失败重试策略,这里默认不重新请求
现在让我们来看一下requestQueue.add()
这个方法里面首先为这个request设置一个队列位置标识,然后判断是否需要缓存(默认为需要),若不需要则直接添加进网络请求队列并返回此request。
若此请求需要缓存,则根据此request的key从等待队列中查找是否已经有被缓存,如果之前已经请求过,就把它加进key对应的队列中。如果没有就把key加进等待队列,同时把request加进缓存队列。
我们来看最后一步RequestQueue.start();
这里面做的第一件事是把mCacheDispatcher线程停掉,并把线程池全停掉
mDispatchers就是一开始初始化RequestQueue时生成的NetWorkDsispatcher数组,大小为4。
然后重新为mCacheDispatcher赋值,我们先来看看这个mCacheDispatcher都干了些什么:
CacheDispatcher继承了Thread,重写其run()方法:
总的来说在进行网络请求之前会先根据文件缓存进行判断,判断文件缓存是否已经过期,过期则直接进入网络请求队列,如果没过期但是已经不新鲜则先返回结果,然后进入网络请求队列刷新缓存。
关于文件缓存策略这一块还有有挺多可以说的,我们留到下一次再说。
然后我们再来看看网络请求这一块,也就是RequestQueue.start()余下的部分
这里分别为4个线程进行初始化,并传入工厂队列,在里面进行request的消费。
我们也来看一下NetworkDispatcher的实现。NetworkDispatcher继承了Thread类,重写run()方法:
可以看到这也是一个消费者,不停地从网络请求队列中取出reqeust进行网络请求,我们来看看mNetwork.performRequest(request);这里面做了什么
我们大概地讲一下这方法都做了什么
首先是添加header
然后获取响应状态及状态码,如果是304(所请求的资源未修改),则直接读取缓存并返回给用户。
判断是否是为301、302、204(可能不返回信息)
记录响应时间
判断200~299,即为服务器没有正常处理该请求,则抛出异常
如果上面没有这几种情况发生,那么返回新的请求中的内容+头部以及状态码
这个时候我们应该继续去看之前被我们忽略的networkResponse处理,在此之前,我们先看看HurlStack如何获取response。
这里要赞一下Volley这个框架,Http协议实践这一块写得超级棒,我们日常使用http连接时不会注意或使用的属性全都写上去,连协议版本都有,还保存、利用了header里缓存及其他各种属性,对于初学者来说是极好的示范。
我们继续来说一下这里面做了什么:
使用url打开连接,获取connection
设置connection的协议、超时时间、header
获取返回状态判断,返回包括header在内的数据
现在我们往回看一下在NetworkDispatcher中被我们忽略的剩余部分
上面解释了mNetwork.performRequest(request)通过其内部的basicNetWork及basicNetWork内部的HttpStack完成了网络请求及返回状态处理,现在我们来解释一下:
拿到返回结果之后判断请求是否有更改,即请求如果是相同的那就交给deliver分发去,并且不再处理相同请求
如果有更改且允许缓存,那就写入缓存,然后通过deliver发送结果。
那么到这里Volley的流程解析就差不多完结了,我们最后来全局描述一下这个结构
RequestQueue将加入的请求加入到mCacheQueue有缓存的情况下处理缓存,没有再加入到mNetworkQueue,采用生产者消费者模式使用线程池对其进行请求,通过BasicNetWork中的HtppStack进行真正的网络请求,并将结果返回,再由NetWorkDispatcher使用Deliver返回数据。
没图,就这样。
做了一点微小的工作。
1、新建RequestQueue
2、新建Request对象及数据回调
3、把Request对象添加进RequestQueue
4、RequestQueue.Start();
如果你已经有了一个RequestQueue,直接做2、3步即可
RequestQueue mQueue = Volley.newRequestQueue(context); StringRequest stringRequest = new StringRequest("http://www.baidu.com", new Response.Listener<String>() { @Override public void onResponse(String response) { Log.d("TAG", response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e("TAG", error.getMessage(), error); } }); mQueue.add(stringReqauest);
这样就完成了一次网络请求并处理获取的数据
让我们来看看内部是怎么实现的
首先是获取请求队列RequestQueue
一般来说我们会使用Volley.newRequestQueue(context);
public static RequestQueue newRequestQueue(Context context) { return newRequestQueue(context, null); } //同上 return newRequestQueue(context, stack, -1);
我们来看这一段:
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) { File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); String userAgent = "volley/0"; try { String packageName = context.getPackageName(); PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); userAgent = packageName + "/" + info.versionCode; } catch (NameNotFoundException e) { } if (stack == null) { if (Build.VERSION.SDK_INT >= 9) { stack = new HurlStack(); } else { // Prior to Gingerbread, HttpUrlConnection was unreliable. // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); } } Network network = new BasicNetwork(stack); RequestQueue queue; if (maxDiskCacheBytes <= -1) { // No maximum size specified queue = new RequestQueue(new DiskBasedCache(cacheDir), network); } else { // Disk cache size specified queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network); } queue.start(); return queue; }
这一段里面根据实际手机的Android版本创建了一个HttpStack,HttpUrlConnection在Android2.2以前有个bug,调用 close() 函数会影响连接池,导致连接复用失效,所以在 Froyo 之前使用 HttpURLConnection 需要关闭 keepAlive,详细的可以看上面注释里给出的链接。谷歌认为HttpUrlConnection更适合安卓,有兴趣可以看看这个:http://android-developers.blogspot.com/2011/09/androids-http-clients.html
然后创建一个network对象,并用network和stack对象作为参数生成RequestQueue返回给我们。
由于我们没有指定线程池的大小,默认会生成1个NetWorkDsispatcher(extendsThread
)数组,这个数组大小为4,同时文件缓存被指定为5MB大小。
这里Volley选择自己来管理线程池,而不是使用java提供的ThreadPool。
现在让我们来看看Request对象。
在Volley里面有多种Request,StringRequest,JsonObjectRequest等,里面的处理逻辑只在parseNetworkResponse这个方法中有较大差别,在这里实现数据类型转换,也就是说,如果你有需要,也可以自己继承Request来写一个自己的转换,例如XML解析什么的。
在上面StringRequest对象生成中,我们调用了:
public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) { this(Method.GET, url, listener, errorListener); }
这里额外指定了以GET方法进行网络请求
public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) { super(method, url, errorListener); mListener = listener; }
然后把参数交由父类处理,自己处理成功回调mListener
那我们来看看父类
public Request(int method, String url, Response.ErrorListener listener) { mMethod = method; mUrl = url; mIdentifier = createIdentifier(method, url); mErrorListener = listener; setRetryPolicy(new DefaultRetryPolicy()); mDefaultTrafficStatsTag = findDefaultTrafficStatsTag(url); }
这里生成了一个唯一ID,并且设置了一个网络请求失败重试策略,这里默认不重新请求
现在让我们来看一下requestQueue.add()
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; } // Insert request into stage if there's already a request with the same cache key in flight. synchronized (mWaitingRequests) { String cacheKey = request.getCacheKey(); if (mWaitingRequests.containsKey(cacheKey)) { // There is already a request in flight. Queue up. Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey); if (stagedRequests == null) { stagedRequests = new LinkedList<Request<?>>(); } stagedRequests.add(request); mWaitingRequests.put(cacheKey, stagedRequests); if (VolleyLog.DEBUG) { VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey); } } else { // Insert 'null' queue for this cacheKey, indicating there is now a request in // flight. mWaitingRequests.put(cacheKey, null); mCacheQueue.add(request); } return request; } }
这个方法里面首先为这个request设置一个队列位置标识,然后判断是否需要缓存(默认为需要),若不需要则直接添加进网络请求队列并返回此request。
若此请求需要缓存,则根据此request的key从等待队列中查找是否已经有被缓存,如果之前已经请求过,就把它加进key对应的队列中。如果没有就把key加进等待队列,同时把request加进缓存队列。
我们来看最后一步RequestQueue.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(); } }
这里面做的第一件事是把mCacheDispatcher线程停掉,并把线程池全停掉
public void stop() { if (mCacheDispatcher != null) { mCacheDispatcher.quit(); } for (int i = 0; i < mDispatchers.length; i++) { if (mDispatchers[i] != null) { mDispatchers[i].quit(); } } }
mDispatchers就是一开始初始化RequestQueue时生成的NetWorkDsispatcher数组,大小为4。
然后重新为mCacheDispatcher赋值,我们先来看看这个mCacheDispatcher都干了些什么:
CacheDispatcher继承了Thread,重写其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(); Request<?> request; while (true) { // release previous request object to avoid leaking request object when mQueue is drained. request = null; try { // Take a request from the queue. // 这里使用了BlockingQueue实现的生产者消费者模式,request在RequestQueue.add()被调用时生产,//若Dispatchers线程已经被启动,而CacheQueue中已经没有request就会被阻塞 request = mCacheQueue.take(); } catch (InterruptedException e) { // We may have been interrupted because it was time to quit. if (mQuit) { return; } continue; } try { 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. // 这个mCache就是生成ReqiuestQueue时作为参数的DiskBasedCache,Volley只实现了文件一级缓存,//有需要的可以自己加一个内存缓存 //如果文件缓存不存在就把这个request加入网络请求队列,继续执行下一个request Cache.Entry entry = mCache.get(request.getCacheKey()); if (entry == null) { request.addMarker("cache-miss"); // Cache miss; send off to the network dispatcher. 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); mNetworkQueue.put(request); continue; } // We have a cache hit; parse its data for delivery back to the request. <span style="white-space:pre"> </span> //缓存可用 request.addMarker("cache-hit"); Response<?> response = request.parseNetworkResponse( new NetworkResponse(entry.data, entry.responseHeaders)); request.addMarker("cache-hit-parsed"); <span style="white-space:pre"> </span> //缓存无须刷新就直接发送 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. <span style="white-space:pre"> </span>// request.addMarker("cache-hit-refresh-needed"); request.setCacheEntry(entry); // Mark the response as intermediate. response.intermediate = true; <span style="white-space:pre"> </span>//如果需要刷新就发送请求结果给用户,并重新请求数据 // Post the intermediate response back to the user and have // the delivery then forward the request along to the network. final Request<?> finalRequest = request; mDelivery.postResponse(request, response, new Runnable() { @Override public void run() { try { mNetworkQueue.put(finalRequest); } catch (InterruptedException e) { // Not much we can do about this. } } }); } } catch (Exception e) { VolleyLog.e(e, "Unhandled exception %s", e.toString()); } } }
总的来说在进行网络请求之前会先根据文件缓存进行判断,判断文件缓存是否已经过期,过期则直接进入网络请求队列,如果没过期但是已经不新鲜则先返回结果,然后进入网络请求队列刷新缓存。
关于文件缓存策略这一块还有有挺多可以说的,我们留到下一次再说。
然后我们再来看看网络请求这一块,也就是RequestQueue.start()余下的部分
for (int i = 0; i < mDispatchers.length; i++) { NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery); mDispatchers[i] = networkDispatcher; networkDispatcher.start(); }
这里分别为4个线程进行初始化,并传入工厂队列,在里面进行request的消费。
我们也来看一下NetworkDispatcher的实现。NetworkDispatcher继承了Thread类,重写run()方法:
for (int i = 0; i < mDispatchers.length; i++) { NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery); mDispatchers[i] = networkDispatcher; networkDispatcher.start(); }
可以看到这也是一个消费者,不停地从网络请求队列中取出reqeust进行网络请求,我们来看看mNetwork.performRequest(request);这里面做了什么
@Override public NetworkResponse performRequest(Request<?> request) throws VolleyError { long requestStart = SystemClock.elapsedRealtime(); while (true) { HttpResponse httpResponse = null; byte[] responseContents = null; Map<String, String> responseHeaders = Collections.emptyMap(); try { // Gather headers. Map<String, String> headers = new HashMap<String, String>(); addCacheHeaders(headers, request.getCacheEntry()); <span style="white-space:pre"> </span>//mHttpStack是之前判断Android版本后生成的HttpClientStack或者HurlStack httpResponse = mHttpStack.performRequest(request, headers); StatusLine statusLine = httpResponse.getStatusLine(); int statusCode = statusLine.getStatusCode(); responseHeaders = convertHeaders(httpResponse.getAllHeaders()); // Handle cache validation. if (statusCode == HttpStatus.SC_NOT_MODIFIED) { Entry entry = request.getCacheEntry(); if (entry == null) { return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); } // A HTTP 304 response does not have all header fields. We // have to use the header fields from the cache entry plus // the new ones from the response. // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5 entry.responseHeaders.putAll(responseHeaders); return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data, entry.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); } // Handle moved resources if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) { String newUrl = responseHeaders.get("Location"); request.setRedirectUrl(newUrl); } // Some responses such as 204s do not have content. We must check. if (httpResponse.getEntity() != null) { responseContents = entityToBytes(httpResponse.getEntity()); } 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, statusLine); 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 (ConnectTimeoutException e) { attemptRetryOnException("connection", request, new TimeoutError()); } catch (MalformedURLException e) { throw new RuntimeException("Bad URL " + request.getUrl(), e); } catch (IOException e) { int statusCode = 0; NetworkResponse networkResponse = null; if (httpResponse != null) { statusCode = httpResponse.getStatusLine().getStatusCode(); } else { throw new NoConnectionError(e); } if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) { VolleyLog.e("Request at %s has been redirected to %s", request.getOriginUrl(), request.getUrl()); } else { VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl()); } if (responseContents != null) { networkResponse = new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart); if (statusCode == HttpStatus.SC_UNAUTHORIZED || statusCode == HttpStatus.SC_FORBIDDEN) { attemptRetryOnException("auth", request, new AuthFailureError(networkResponse)); } else if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) { attemptRetryOnException("redirect", request, new RedirectError(networkResponse)); } else { // TODO: Only throw ServerError for 5xx status codes. throw new ServerError(networkResponse); } } else { throw new NetworkError(e); } } } }
我们大概地讲一下这方法都做了什么
首先是添加header
然后获取响应状态及状态码,如果是304(所请求的资源未修改),则直接读取缓存并返回给用户。
判断是否是为301、302、204(可能不返回信息)
记录响应时间
判断200~299,即为服务器没有正常处理该请求,则抛出异常
如果上面没有这几种情况发生,那么返回新的请求中的内容+头部以及状态码
这个时候我们应该继续去看之前被我们忽略的networkResponse处理,在此之前,我们先看看HurlStack如何获取response。
@Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { String url = request.getUrl(); HashMap<String, String> map = new HashMap<String, String>(); map.putAll(request.getHeaders()); map.putAll(additionalHeaders); if (mUrlRewriter != null) { //web技术,重写url,但是这里在创建HurlStack的时候传值为null,有需要可以自己传个进来 String rewritten = mUrlRewriter.rewriteUrl(url); if (rewritten == null) { throw new IOException("URL blocked by rewriter: " + url); } url = rewritten; } URL parsedUrl = new URL(url); //获取connection,如果mSslSocketFactory不为空还会为其设置SSLSocketFactory,网络安全用 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. ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1); 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."); } //获取响应状态 StatusLine responseStatus = new BasicStatusLine(protocolVersion, connection.getResponseCode(), connection.getResponseMessage()); BasicHttpResponse response = new BasicHttpResponse(responseStatus); if (hasResponseBody(request.getMethod(), responseStatus.getStatusCode())) { //获取响应中的实体 response.setEntity(entityFromConnection(connection)); } for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) { if (header.getKey() != null) { //为响应结果添加header,也要用在缓存中 Header h = new BasicHeader(header.getKey(), header.getValue().get(0)); response.addHeader(h); } } return response; }
这里要赞一下Volley这个框架,Http协议实践这一块写得超级棒,我们日常使用http连接时不会注意或使用的属性全都写上去,连协议版本都有,还保存、利用了header里缓存及其他各种属性,对于初学者来说是极好的示范。
我们继续来说一下这里面做了什么:
使用url打开连接,获取connection
设置connection的协议、超时时间、header
获取返回状态判断,返回包括header在内的数据
现在我们往回看一下在NetworkDispatcher中被我们忽略的剩余部分
@Override public void run() { <span style="white-space:pre"> </span> //前略 // 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()) { //判断这个结果是否为304且响应已经被发送 //这里调用了finish之后,内部调用RequestQueue将request从队列中删除,并且根据cachekey将所有//相同请求全移除,加入到缓存队列中,这样就回到之前我们分析的缓存队列发现已经有缓存,则直接返//回缓存,不进行网络请求 request.finish("not-modified"); continue; } // Parse the response here on the worker thread. //这里就是之前我们提到的进行数据处理的地方,如果自己想搞个xmlRequest就实现这个方法 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是一个内含handler(主线程)的回调处理器,内部通过Executor发送线程,并在线程//内使用handler将回调发送到主线程 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); } } }
上面解释了mNetwork.performRequest(request)通过其内部的basicNetWork及basicNetWork内部的HttpStack完成了网络请求及返回状态处理,现在我们来解释一下:
拿到返回结果之后判断请求是否有更改,即请求如果是相同的那就交给deliver分发去,并且不再处理相同请求
如果有更改且允许缓存,那就写入缓存,然后通过deliver发送结果。
那么到这里Volley的流程解析就差不多完结了,我们最后来全局描述一下这个结构
RequestQueue将加入的请求加入到mCacheQueue有缓存的情况下处理缓存,没有再加入到mNetworkQueue,采用生产者消费者模式使用线程池对其进行请求,通过BasicNetWork中的HtppStack进行真正的网络请求,并将结果返回,再由NetWorkDispatcher使用Deliver返回数据。
没图,就这样。
做了一点微小的工作。
相关文章推荐
- 8、volley 源码解析之网络线程工作流程
- Volley源码解析(三)网络请求流程
- 6、volley 源码解析之工作流程综述
- 7、volley 源码解析之缓存线程工作流程
- 9、volley 源码解析之消息分发工的工作流程
- Android恢复出厂设置流程分析【Android源码解析十】
- live555 接收rtsp视频流详细源码流程详细解析
- Nginx 源码分析-- 模块module 解析执行 nginx.conf 配置文件流程分析 一
- Hadoop源码解析-作业执行流程-集群模式
- Android恢复出厂设置流程分析【Android源码解析十】
- Redis运行流程源码解析 .
- Redis源码解析 - 客户端工作流程及命令编码
- Hadoop源码解析-作业执行流程-本地模式
- Android4.2Email源码流程解析
- Android短彩信源码解析-短信发送流程(二)
- AndroidICS4.0---->LockScreen锁屏流程【Android源码解析九】
- live555 接收rtsp视频流详细源码流程详细解析
- mesa源码阅读笔记(7)_顶点变换流程解析
- uboot源码分析(1)uboot 命令解析流程简析
- Nginx 源码分析-- 模块module 解析执行 nginx.conf 配置文件流程分析 二