当调用 RequestQueue的 add()方法添加 Request 的时候,会根据请求的一个参数 shouldCache,来判断要不要去缓存中查询,如果是去缓存中查询,那么就会把请求放到CacheQueue中,如下:
- mWaitingRequests.put(cacheKey, null);
- mCacheQueue.add(request);
这个时候,线程CacheDispatcher其实已经在跑了,到它的run方法中来看一下:
- public void run() {
- if (DEBUG) VolleyLog.v("start new dispatcher");
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- // 初始化缓存
- mCache.initialize();
- while (true) {
- try {
- // 从缓存队列中获取一个请求
- final Request<?> request = mCacheQueue.take();
- request.addMarker("cache-queue-take");
- // 如果请求已经被取消,则重新获取请求
- if (request.isCanceled()) {
- request.finish("cache-discard-canceled");
- continue;
- }
- // 根据request的cacheKey从缓存中得到对应的记录
- Cache.Entry entry = mCache.get(request.getCacheKey());
- if (entry == null) {
- request.addMarker("cache-miss");
- // 这里说明缓存中没有对应的记录,那么需要去网络中获取,那么就将它放到Network的队列中
- mNetworkQueue.put(request);
- continue;
- }
- // 如果缓存中有记录,但是已经过期了或者失效了,也需要去网络获取,放到Network队列中
- if (entry.isExpired()) {
- request.addMarker("cache-hit-expired");
- request.setCacheEntry(entry);
- mNetworkQueue.put(request);
- continue;
- }
- // 如果上面的情况都不存在,说明缓存中存在这样记录,那么就调用request的parseNetworkResponse方法,获取一个响应Response
- request.addMarker("cache-hit");
- Response<?> response = request.parseNetworkResponse(
- new NetworkResponse(entry.data, entry.responseHeaders));
- request.addMarker("cache-hit-parsed");
- if (!entry.refreshNeeded()) {
- // 缓存记录,不需要更新,那么就直接调用mDelivery,传回给主线程去更新。
- mDelivery.postResponse(request, response);
- } else {
- // 还存在这样一种情况,缓存记录存在,但是它约定的生存时间已经到了(还未完全过期,叫软过期),可以将其发送到主线程去更新
- // 但同时,也要从网络中更新它的数据
- request.addMarker("cache-hit-refresh-needed");
- request.setCacheEntry(entry);
- // Mark the response as intermediate.
- response.intermediate = true;
- // 将其传回主线程的同时,将请求放到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)主要做了几件事情:
1)初始化本地缓存
2)开始一个无限的循环,调用 mCacheQueue的take方法,来获得一个请求,而mCacheQueue是一个BlockingQueue,也就是说,当队列中没有请求的时候,take方法就会一直阻塞在这里,等待队列中的请求,而一旦队列中有新的请求进来了,那么它就会马上执行下去。
- /** The queue of requests coming in for triage. */
- private final BlockingQueue<Request<?>> mCacheQueue;
- /** The queue of requests going out to the network. */
- private final BlockingQueue<Request<?>> mNetworkQueue;
3)判断请求是否已经取消,如果已经被取消了,则不需要再走下去。
4)根据请求的CacheKey去缓存中寻找相对应的记录,如果找不到对应的记录,或者对应的记录过期了,则将其放到NetworkQueue队列中。
5)缓存中存在相对应的记录,那么调用每个请求具体的实现方法 parseNetworkResponse函数,根据具体的请求去解析得到对应的响应Response对象。
6)获得Response对象之后,还会再进行判断这个请求是不是进行一次网络的更新,这是根据记录的soft-ttl (time-to-live)属性,如下:
- /** True if the entry is expired. */
- public boolean isExpired() {
- return this.ttl < System.currentTimeMillis();
- }
- /** True if a refresh is needed from the original data source. */
- public boolean refreshNeeded() {
- return this.softTtl < System.currentTimeMillis();
- }
从这里也可以看到,expired的判断跟refreshNeed的判断是两个字段,一个是ttl,一个是softTtl。
如果需要进行更新,那么就会在发送响应结果回主线程更新的同时,再将请求放到NetworkQueue中,从网络中更新请求对应的数据。如果不需要,则直接将结果调用mDelivery传回主线程进行UI的更新。
CacheDispatcher做的事情并不多,因为Volley主要的功能其实还是跟网络打交道,所以主要的实现,其实还是NetworkDispatcher。