Volley框架的基本解读
Posted zero-27
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Volley框架的基本解读相关的知识,希望对你有一定的参考价值。
在之前四篇博客中,我们已经将RequestQueue中start方法中的网络请求这条主线完全解析了一遍,接下来我们看另一条缓存主线,CacheDispatcher的源码:
public class CacheDispatcher extends Thread
同NetworkDispatcher一样,CacheDispatcher同样是一个线程
public CacheDispatcher(
BlockingQueue<Request> cacheQueue, BlockingQueue<Request> networkQueue,
Cache cache, ResponseDelivery delivery)
mCacheQueue = cacheQueue;
mNetworkQueue = networkQueue;
mCache = cache;
mDelivery = delivery;
里面也只有一个构造方法,四个参数分别是缓存队列,网络队列,缓存处理类,结果分发类,同样的在RequestQueue调用了它的start方法,因为是Thread所以我们看run方法:
@Override
public void run()
if (DEBUG) 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.
// 从缓存队列中取出request
final Request request = mCacheQueue.take();
// 调试信息
request.addMarker("cache-queue-take");
// If the request has been canceled, don't bother dispatching it.
// 如果该request以取消,则中断任务
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解析,并输出调试日志
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.initialize方法里面看看,这里说一点Cache同Network一样是一个接口,里面的方法稍微多一点,我们来看具体子类实现,同样是在Volley.newRequestQueue中创建的:
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
public DiskBasedCache(File rootDirectory)
this(rootDirectory, DEFAULT_DISK_USAGE_BYTES);
public DiskBasedCache(File rootDirectory, int maxCacheSizeInBytes)
mRootDirectory = rootDirectory;
mMaxCacheSizeInBytes = maxCacheSizeInBytes;
rootDirectory是缓存径路,DEFAULT_DISK_USAGE_BYTES默认值是5 * 1024 * 1024,也就是5M,表示最大缓存容量。
我们来看看它的initialize方法:
/**
* Initializes the DiskBasedCache by scanning for all files currently in the
* specified root directory. Creates the root directory if necessary.
*
* 初始化缓存,将缓存文件全部读入内存中
*/
@Override
public synchronized void initialize()
// 如果文件不存在,说明无缓存
if (!mRootDirectory.exists())
if (!mRootDirectory.mkdirs())
VolleyLog.e("Unable to create cache dir %s", mRootDirectory.getAbsolutePath());
return;
// 获取缓存文件数组
File[] files = mRootDirectory.listFiles();
if (files == null)
return;
for (File file : files)
FileInputStream fis = null;
try
fis = new FileInputStream(file);
CacheHeader entry = CacheHeader.readHeader(fis);
entry.size = file.length();
putEntry(entry.key, entry);
catch (IOException e)
if (file != null)
file.delete();
finally
try
if (fis != null)
fis.close();
catch (IOException ignored)
前面很简单,判断缓存路径是否存在,否创建缓存路径,如果创建失败,那么初始化也就失败了。
然后获取缓存路径下的所有缓存文件,用字节流读取解析,CacheHeader是DiskBasedCache中的静态内部类,里面定义了很多字段,比如size数据长度,key缓存的键,其实就是URL,还有serverDate服务器的返回时间等等,readHeader方法就是对读取缓存文件进行了封装,考虑到涉及到的方法太多,我就不一一贴出来了,得到了CacheHeader这个缓存实体,putEntry方法就是将它放入内存:
/**
* Puts the entry with the specified key into the cache.
* @param key The key to identify the entry by.
* @param entry The entry to cache.
*
* 将缓存读入内存
*/
private void putEntry(String key, CacheHeader entry)
// 如果内存中没有该缓存,累加当前缓存大小,如果存在,计算缓存容量差,再进行累计
if (!mEntries.containsKey(key))
mTotalSize += entry.size;
else
CacheHeader oldEntry = mEntries.get(key);
mTotalSize += (entry.size - oldEntry.size);
mEntries.put(key, entry);
mEntries是一个Map集合,定义在DiskBasedCache的成员变量中
/** Map of the Key, CacheHeader pairs 初始位16,扩展0.75倍,使用排序*/
private final Map<String, CacheHeader> mEntries =
new LinkedHashMap<String, CacheHeader>(16, .75f, true);
initialize方法我们分析完了,回过头继续看CacheDispatcher的run方法,同NetworkDispatcher一样的写法,后面也是一个while死循环,mCacheQueue同样是一个优先级队列,试图从队列中获取一个request,判断request是否取消,是结束该次请求,request.getCacheKey()返回的就是URL,试图从缓存中查找对应的缓存,如果找不到,扔进网络队列中,它就不管了,如果获取到的缓存已经过期,还是扔进网络队列,当个甩手掌柜,到这里可以确定缓存有效,封装成Response准备返回,下面这个!entry.refreshNeeded()对缓存过期的再次判断,是我也不太理解的地方,但代码是很清晰的,如果没有过期,分发结果,如果过期了,它依然会返回结果,但会向网络请求一次,也就是说,该request会得到两个response,一个是缓存的,一个是网络的。
到这里大家可能已经急不可待想揭开mDelivery的神秘面纱了,但我们下一篇再说,在CacheDispatcher还有一个我们熟悉的方法:
/**
* Forces this dispatcher to quit immediately. If any requests are still in
* the queue, they are not guaranteed to be processed.
*
* 标记退出,并中断线程
*/
public void quit()
mQuit = true;
interrupt();
作用就不必我多说了吧,我们下篇博客再见!
以上是关于Volley框架的基本解读的主要内容,如果未能解决你的问题,请参考以下文章