4、Volley解析(二),源码的深入分析一,缓存线程和网络请求线程
2017-04-28 15:21
555 查看
前言
首先来看一下谷歌的官方流程图从图中我们可以看出Volley工作的时候有三种线程,分别是主线程、请求线程、缓存线程,图中的流程大致如下:首先将请求放入缓存队列(队列中会根据优先级来排序),缓存线程将请求从缓存线程中取出,如果缓存存在,则将缓存的数据取出解析,传到主线程。如果不存在则将请求队列去执行网络请求。请求完成之后,再把结果发送给主线程。这里就是利用线程生产者-消费者模式。
1. 源码的入口
分析某个开源项目的源码,首先要找到它的入口,然后再抽丝剥茧,逐步分析。这样思路会比较清晰。//这个方法要做的工作是创建工作线程池的默认实例,并调用 public static RequestQueue newRequestQueue(Context context, HttpStack stack) { 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) { } //如果没有限定stack,由系统自己判断使用哪种请求方式 if (stack == null) { if (Build.VERSION.SDK_INT >= 9) { //adk版本在9或者以上,使用HttpURLConnection //它的API简单,体积较小,因而非常适用于Android项目。压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。 stack = new HurlStack(); } else { // 在Android 2.2版本之前,HttpClient拥有较少的bug,因此使用它是最好的选择。 stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); } } Network network = new BasicNetwork(stack); RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network); // queue.start(); return queue; }
今天这一篇博客,先不去研究用哪种请求方式,先介绍各个线程的工作流程。
创建好了HttpStack之后,接下来又创建了一个Network对象,它是用于根据传入的HttpStack对象来处理网络请求的,紧接着new出一个RequestQueue对象,并调用它的start()方法进行启动,然后将RequestQueue返回。
看到这里我们肯定会疑问,start()到底做了什么工作,会不会和线程有关呢?下面我们就来看一下。
public void start() { //确保当前运行的任何调度都已停止。 stop(); // 创建缓存的调度器并启动(缓存线程) mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); mCacheDispatcher.start(); // 创建网络请求的调度器,默认开启四条网络请求的线程 for (int i = 0; i < mDispatchers.length; i++) { NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery); mDispatchers[i] = networkDispatcher; networkDispatcher.start(); } }
这里的CacheDispatcher和NetworkDispatcher都是继承自Thread的,也就是说当调用了satrt()之后,就会有五个线程一直在后台运行,不断等待网络请求的到来,其中CacheDispatcher是缓存线程,NetworkDispatcher是网络请求线程。
我们首先来看一下CacheDispatcher
@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 { //首先从mCacheQueue中取出一个任务, // at least one is available. final Request<?> request = mCacheQueue.take(); request.addMarker("cache-queue-take"); // 判断请求任务是否取消,取消了就跳出,进入下个循环。 if (request.isCanceled()) { request.finish("cache-discard-canceled"); continue; } // 取出缓存 Cache.Entry entry = mCache.get(request.getCacheKey()); //判断是否为空 if (entry == null) { request.addMarker("cache-miss"); // 如果为空,就将这个任务加入到网络请求的队列当中,这里就用到了生产者-消费者模式,此时缓存线程充当的是生产者对象。 mNetworkQueue.put(request); //然后跳出循环 continue; } //如果缓存过期的话同样是将任务加入网络请求队列当中。然后跳出当前循环 if (entry.isExpired()) { request.addMarker("cache-hit-expired"); request.setCacheEntry(entry); mNetworkQueue.put(request); continue; } // 下面就是肯定存在缓存,浴室将缓存读取出来,解析。 request.addMarker("cache-hit"); Response<?> response = request.parseNetworkResponse( new NetworkResponse(entry.data, entry.responseHeaders)); request.addMarker("cache-hit-parsed"); //如果缓存的数据不需要刷新 if (!entry.refreshNeeded()) { // 将数据发送到主线程 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; // 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) { // Not much we can do about this. } } }); } } catch (InterruptedException e) { // We may have been interrupted because it was time to quit. if (mQuit) { //循环结束,安全 return; } continue; } } }
到这里相信大家已经对CacheDispatcher有了足够的了解,下面我们就来看看NetworkDispatcher 主要职责是什么代码如下
@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. //支持304重定向 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); } } } private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) { error = request.parseNetworkError(error); mDelivery.postError(request, error); }
这样 CacheDispatcher 和 NetworkDispatcher就构成了生产者和消费者模式,当然充当生产者的不仅仅是CacheDispatcher 线程,还有主线程。其实CacheDispatcher 和 NetworkDispatcher大部分逻辑都是相同的,理解了一个另一个就不难理解了。今天这篇博客就到这里,下篇将为大家分析具体的网络请求是怎么样的。
相关文章推荐
- Volley源码解析(三) 有缓存机制的情况走缓存请求的源码分析
- 【安卓网络请求开源框架Volley源码解析系列】定制自己的Request请求及Volley框架源码剖析
- 【安卓网络请求开源框架Volley源码解析系列】初识Volley及其基本用法
- 8、volley 源码解析之网络线程工作流程
- 7、volley 源码解析之缓存线程工作流程
- Volley网络请求封装之LruCache源码分析
- Glide源码分析4 -- 缓存,编解码和网络请求
- Volley源码解析(一):网络请求内容
- [Android]Volley源码分析(三)网络请求
- 【安卓网络请求开源框架Volley源码解析系列】定制自己的Request请求及Volley框架源码剖析
- Volley网络请求框架源码解析
- 【安卓网络请求开源框架Volley源码解析系列】初识Volley及其基本用法
- Volley -- 网络请求源码分析
- # Volley源码解析(二) 没有缓存的情况下直接走网络请求源码分析#
- 【安卓网络请求开源框架Volley源码解析系列】定制自己的Request请求及Volley框架源码剖析
- 【安卓网络请求开源框架Volley源码解析系列】初识Volley及其基本用法
- Volley源码解析(三)网络请求流程
- 【安卓网络请求开源框架Volley源码解析系列】初识Volley及其基本用法
- OKHttp网络框架源码解析(一)okHttp框架同步异步请求流程和源码分析
- 看Volley源码,对HTTP缓存机制分析