当调用 RequestQueue的 add()方法添加 Request 的时候,会根据请求的一个参数 shouldCache,来判断要不要去缓存中查询,如果是去缓存中查询,那么就会把请求放到CacheQueue中,如下:

[java]  view plain copy
  1. mWaitingRequests.put(cacheKey, null);  
  2. mCacheQueue.add(request);  

这个时候,线程CacheDispatcher其实已经在跑了,到它的run方法中来看一下:

[java]  view plain copy
  1. public void run() {  
  2.     if (DEBUG) VolleyLog.v("start new dispatcher");  
  3.     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
  4.   
  5.     // 初始化缓存  
  6.     mCache.initialize();  
  7.   
  8.     while (true) {  
  9.         try {  
  10.             // 从缓存队列中获取一个请求  
  11.             final Request<?> request = mCacheQueue.take();  
  12.             request.addMarker("cache-queue-take");  
  13.   
  14.             // 如果请求已经被取消,则重新获取请求  
  15.             if (request.isCanceled()) {  
  16.                 request.finish("cache-discard-canceled");  
  17.                 continue;  
  18.             }  
  19.   
  20.             // 根据request的cacheKey从缓存中得到对应的记录  
  21.             Cache.Entry entry = mCache.get(request.getCacheKey());  
  22.             if (entry == null) {  
  23.                 request.addMarker("cache-miss");  
  24.                 // 这里说明缓存中没有对应的记录,那么需要去网络中获取,那么就将它放到Network的队列中  
  25.                 mNetworkQueue.put(request);  
  26.                 continue;  
  27.             }  
  28.   
  29.             // 如果缓存中有记录,但是已经过期了或者失效了,也需要去网络获取,放到Network队列中  
  30.             if (entry.isExpired()) {  
  31.                 request.addMarker("cache-hit-expired");  
  32.                 request.setCacheEntry(entry);  
  33.                 mNetworkQueue.put(request);  
  34.                 continue;  
  35.             }  
  36.   
  37.             // 如果上面的情况都不存在,说明缓存中存在这样记录,那么就调用request的parseNetworkResponse方法,获取一个响应Response  
  38.             request.addMarker("cache-hit");  
  39.             Response<?> response = request.parseNetworkResponse(  
  40.                     new NetworkResponse(entry.data, entry.responseHeaders));  
  41.             request.addMarker("cache-hit-parsed");  
  42.   
  43.             if (!entry.refreshNeeded()) {  
  44.                 // 缓存记录,不需要更新,那么就直接调用mDelivery,传回给主线程去更新。  
  45.                 mDelivery.postResponse(request, response);  
  46.             } else {  
  47.                 // 还存在这样一种情况,缓存记录存在,但是它约定的生存时间已经到了(还未完全过期,叫软过期),可以将其发送到主线程去更新  
  48.                 // 但同时,也要从网络中更新它的数据  
  49.                 request.addMarker("cache-hit-refresh-needed");  
  50.                 request.setCacheEntry(entry);  
  51.   
  52.                 // Mark the response as intermediate.  
  53.                 response.intermediate = true;  
  54.   
  55.                 // 将其传回主线程的同时,将请求放到Network队列中。  
  56.                 mDelivery.postResponse(request, response, new Runnable() {  
  57.                     @Override  
  58.                     public void run() {  
  59.                         try {  
  60.                             mNetworkQueue.put(request);  
  61.                         } catch (InterruptedException e) {  
  62.                             // Not much we can do about this.  
  63.                         }  
  64.                     }  
  65.                 });  
  66.             }  
  67.   
  68.         } catch (InterruptedException e) {  
  69.             // We may have been interrupted because it was time to quit.  
  70.             if (mQuit) {  
  71.                 return;  
  72.             }  
  73.             continue;  
  74.         }  
  75.     }  
  76. }  

缓存线程(CacheDispatcher)主要做了几件事情:

1)初始化本地缓存

2)开始一个无限的循环,调用 mCacheQueue的take方法,来获得一个请求,而mCacheQueue是一个BlockingQueue,也就是说,当队列中没有请求的时候,take方法就会一直阻塞在这里,等待队列中的请求,而一旦队列中有新的请求进来了,那么它就会马上执行下去。

[java]  view plain copy
  1. /** The queue of requests coming in for triage. */  
  2. private final BlockingQueue> mCacheQueue;  
  3.   
  4. /** The queue of requests going out to the network. */  
  5. private final BlockingQueue> mNetworkQueue;  

3)判断请求是否已经取消,如果已经被取消了,则不需要再走下去。

4)根据请求的CacheKey去缓存中寻找相对应的记录,如果找不到对应的记录,或者对应的记录过期了,则将其放到NetworkQueue队列中。

5)缓存中存在相对应的记录,那么调用每个请求具体的实现方法 parseNetworkResponse函数,根据具体的请求去解析得到对应的响应Response对象。

6)获得Response对象之后,还会再进行判断这个请求是不是进行一次网络的更新,这是根据记录的soft-ttl (time-to-live)属性,如下:

[java]  view plain copy
  1. /** True if the entry is expired. */  
  2. public boolean isExpired() {  
  3.     return this.ttl < System.currentTimeMillis();  
  4. }  
  5.   
  6. /** True if a refresh is needed from the original data source. */  
  7. public boolean refreshNeeded() {  
  8.     return this.softTtl < System.currentTimeMillis();  
  9. }  

从这里也可以看到,expired的判断跟refreshNeed的判断是两个字段,一个是ttl,一个是softTtl。

如果需要进行更新,那么就会在发送响应结果回主线程更新的同时,再将请求放到NetworkQueue中,从网络中更新请求对应的数据。如果不需要,则直接将结果调用mDelivery传回主线程进行UI的更新。

CacheDispatcher做的事情并不多,因为Volley主要的功能其实还是跟网络打交道,所以主要的实现,其实还是NetworkDispatcher。

更多相关文章

  1. Android中 LogCat 信息消失
  2. Android中多线程的用法
  3. Android高效加载大图,防止OOM,以及多图解决方案
  4. Android(安卓)Handler, Looper浅析
  5. Android开源项目xUtils HttpUtils模块分析
  6. 图片加载处理
  7. Android客户端三步完成支付宝支付SDK接入
  8. android实现session保持
  9. android 异常问题 Scrollview中嵌套webview出现大面积空白(第二次

随机推荐

  1. android编译时添加库第三方库文件
  2. 2.4.10 可展开的列表组件
  3. android 蓝牙
  4. 代码中设置drawableright
  5. android 获取系统硬件信息
  6. Android(安卓)实现文件的下载
  7. 学习Android动画小结
  8. Android笔记:Socket客户端收发数据
  9. android 获取IP地址
  10. android developer