当前位置: 代码迷 >> Android >> Android中关于Volley的使用(6)认识 CacheDispatcher
  详细解决方案

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

热度:104   发布时间:2016-04-28 06:22:44.0
Android中关于Volley的使用(六)认识 CacheDispatcher

当调用 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。

结束!


  相关解决方案