Volley源码(二)--考虑缓存
来源:互联网 发布:mysql 行锁 编辑:程序博客网 时间:2024/05/19 03:43
在上一篇文章中Volley源码(一)不考虑缓存,以StringRequest为例,讲解了发送不缓存的post请求。这次主要讲解,发送缓存的get请求。为什么这么说。直接翻daima
if (!request.shouldCache()) { mNetworkQueue.add(request); return request; }
public final boolean shouldCache() { //Allow caching only if method is a GET request if(mMethod == Method.GET) { return mShouldCache & true; } return false; }mShouldCache默认为true。所以,在shouldCache方法中,GET请求的话就return true(缓存),POST请求的话就return false(不缓存)。接下来来看看有缓存的GET请求有哪些地方不一样
1.RequestQueue的add方法
public Request add(Request request) { // Tag the request as belonging to this queue and add it to the set of current requests. request.setRequestQueue(this); synchronized (mCurrentRequests) { mCurrentRequests.add(request); } // Process requests in the order they are added. request.setSequence(getSequenceNumber()); request.addMarker("add-to-queue"); // If the request is uncacheable, skip the cache queue and go straight to the network. if (!request.shouldCache()) { mNetworkQueue.add(request); return request; } // Insert request into stage if there's already a request with the same cache key in flight. synchronized (mWaitingRequests) { String cacheKey = request.getCacheKey(); if (mWaitingRequests.containsKey(cacheKey)) { // There is already a request in flight. Queue up. Queue<Request> stagedRequests = mWaitingRequests.get(cacheKey); if (stagedRequests == null) { stagedRequests = new LinkedList<Request>(); } stagedRequests.add(request); mWaitingRequests.put(cacheKey, stagedRequests); if (VolleyLog.sDebug) { VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey); } } else { // Insert 'null' queue for this cacheKey, indicating there is now a request in // flight. mWaitingRequests.put(cacheKey, null); mCacheQueue.add(request); } return request; } }上篇文章中,因为不需要缓存,所以在
if (!request.shouldCache()) { mNetworkQueue.add(request); return request;}这里直接return了,这次是GET请求,需要缓存,所以if代码块里面的代码不会被执行到,继续往下走,先拿取request的cacheKey(点进去自己看看,其实就是url)。看mWaitingRequests是否包含这个url。mWaitingRequests是一个HashMap,key是这个请求的url,value是同样请求url的Request的链表。
mWaitingRequests包含这个url的话,就将这个url的请求加到此url对应的LinkedList中去,不包含的话,将此url加到mWaitingRequests(对应的value是null)和mCacheQueue中。
mWaitingRequests包含这个url的话说明这个request还没请求完毕,因为在RequestQueue的finish方法中有从mWaitingRequests中remove这个request,这个finish方法只有请求执行完毕才会被调用(参考NetworkDispatcher的run方法)。
void finish(Request request) { // Remove from the set of requests currently being processed. synchronized (mCurrentRequests) { mCurrentRequests.remove(request); } if (request.shouldCache()) { synchronized (mWaitingRequests) { String cacheKey = request.getCacheKey(); Queue<Request> waitingRequests = mWaitingRequests.remove(cacheKey); if (waitingRequests != null) { if (VolleyLog.sDebug) { VolleyLog.v("Releasing %d waiting requests for cacheKey=%s.", waitingRequests.size(), cacheKey); } // Process all queued up requests. They won't be considered as in flight, but // that's not a problem as the cache has been primed by 'request'. mCacheQueue.addAll(waitingRequests); } } } }
2.从缓存队列中取数据
数据加到mCacheQueue后,CacheDispatcher中的run方法就能取到数据啦
public void run() { if (VolleyLog.sDebug) VolleyLog.v("start new dispatcher"); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // Make a blocking call to initialize the cache. mCache.initialize(); while (true) { try { // Get a request from the cache triage queue, blocking until // at least one is available. final Request request = mCacheQueue.take(); request.addMarker("cache-queue-take"); // If the request has been canceled, don't bother dispatching it. if (request.isCanceled()) { request.finish("cache-discard-canceled"); continue; } // Attempt to retrieve this item from cache. Cache.Entry entry = mCache.get(request.getCacheKey()); if (entry == null) { request.addMarker("cache-miss"); // Cache miss; send off to the network dispatcher. mNetworkQueue.put(request); continue; } // If it is completely expired, just send it to the network. if (entry.isExpired()) { request.addMarker("cache-hit-expired"); request.setCacheEntry(entry); mNetworkQueue.put(request); continue; } // We have a cache hit; parse its data for delivery back to the request. request.addMarker("cache-hit"); Response<?> response = request.parseNetworkResponse( new NetworkResponse(entry.data, entry.responseHeaders)); request.addMarker("cache-hit-parsed"); if (!entry.refreshNeeded()) { // Completely unexpired cache hit. Just deliver the response. 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; } } }先不管mCache是什么(肯定提供了get和put方法,用来缓存的嘛,肯定有存有取)
首先从mCacheQueue取到之前add进去的request,再从缓存中拿数据(缓存用到的key还是url),
Cache.Entry entry = mCache.get(request.getCacheKey());再对entry做一系列判断,entry为空(表明之前没有缓存过),缓存过期了(entry.isExpired),把请求加到mNetworkDispatcher(等于把请求丢到mNetworkDispatcher里啦)。NetworkDispatcher的run方法中,肯定有对此请求有做缓存
if (request.shouldCache() && response.cacheEntry != null) { mCache.put(request.getCacheKey(), response.cacheEntry); request.addMarker("network-cache-written");}看到了吧,还是通过mCache缓存该请求。另一方面,如果entry不为空(表明之前有缓存过),或者缓存没有过期。该怎么请求还是怎么请求,只是多一个处理,就是该缓存是否需要更新一下
if (!entry.refreshNeeded()) { // Completely unexpired cache hit. Just deliver the response. 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. } } }); }可以看到,虽然这个类叫CacheDispatcher,实际上,缓存的操作都在NetworkDispatcher里进行的,entry需要刷新的话,将entry设置给request,然后post一个ruannable(为什么不直接加到mNetworkQueue,非要post里面加到mNetworkQueue?因为NetworkDispatcher有用到缓存,这样做可以确保将entry设置给request后,NetworkDispatcher才取到request的)
阅读全文
0 0
- Volley源码(二)--考虑缓存
- Volley源码(一)--不考虑缓存
- Volley源码解析(二)
- Volley源码分析二
- Volley(二) 源码分析
- Volley源码解析(二)
- 深入volley(二)volley缓存细节
- 从源码上看Volley的缓存机制,volley缓存
- 4、Volley解析(二),源码的深入分析一,缓存线程和网络请求线程
- Volley 源码解析(二)
- Volley源码解析(二)
- Volley 源码分析(二)
- Volley源码分析(二)
- 【进阶android】Volley源码分析——Volley的缓存
- 聊聊Volley源码(缓存流程)
- Volley源码分析(二)-Volley中的Request类
- [Android]Volley源码分析(二)Cache
- [Android]Volley源码分析(二)初始化
- 剑指Offer------重建二叉树
- poj1258 Agri-Net
- ThreadLocal的实现原理
- [bzoj2049][LCT]洞穴探测cave
- 【深入PHP 面向对象】读书笔记(十)
- Volley源码(二)--考虑缓存
- 【前缀和 && 思维转换】ICM Technex 2017 and Codeforces Round #400 (Div. 1 + Div. 2, combined)Molly's Chemicals
- C# winform中属性之backgroundworker
- BZOJ 4579 Closing the Farm
- 《leetcode》valid-parentheses
- 机器学习(三):梯度下降法
- Java.lang包中的final类汇总
- iOS UITapGestureRecognizer方法实现UIlable监听功能
- 手动打包输出后端jar