Android中关于Volley的使用(三)认识 CacheDispatcher

当调用 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<Request<?>> mCacheQueue;  
  3.   
  4. /** The queue of requests going out to the network. */  
  5. private final BlockingQueue<Request<?>> 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。

你可能感兴趣的:(Android中关于Volley的使用(三)认识 CacheDispatcher)