总结volley源码解析
来源:互联网 发布:深圳冰川网络 市场策划 编辑:程序博客网 时间:2024/06/05 05:50
在阅读之前
本文章默认你已经会使用volley的前提下所总结的, 如果你还未清楚volley的使用, 建议你阅读前面关于volley介绍的文章, 阅读文章之后如果你有任何问题, 欢迎留言交流.
开始吧
- 首先, 从我们new一个请求队列开始, volley的底层就已经默认开启了5个线程在循环工作等待请求队列的添加, 所以, 我们在使用时必须保证请求队列的全局唯一性, 避免资源的浪费.
- 从请求队列的构造函数我们可以看出, 构造函数的参数分别有缓存接口Cache; 执行网络请求的接口Network; 网络请求线程池数量threadPoolSize, 默认是4; 还有一个请求结果和错误的分发器ResponseDelivery, 它也是一个接口, 从它接收一个通过Handler绑定主线程的ExecutorDelivery对象可以看出, 它的作用是将网络请求的结果和错误通过Handler交付给主线程处理.
所有的参数都通过成员变量保存起来.
从整个构造函数的参数可以看出, 谷歌很充分的利用了面向接口编程, 很大程度上体现了volley具有很强的扩展性. - 从缓存接口接收的DiskBasedCache开始, 我们需要创建磁盘缓存, 缓存目录是Cache目录下的volley文件夹, 默认大小是5M.
- 第二个参数network, 接收一个封装了HttpStack的BasicNetwork对象, 我们来看一下HttpStack接口的实现关系: HttpClientStack和HurlStack实现了这个接口.
- HttpClientStack内部其实就是通过第三方网络请求工具Apache的HttpClient实现了网络请求, 而HurlStack内部是通过HttpURLConnection发起网络请求的.
- 在volley类的源码里, 我们可以看到判断如果当前手机系统SDK版本在9之后, 创建HurlStack网络请求, 而在9之前, 则是创建HttpClientStack作为网络请求工具.
- 谷歌对此也给了解析: 在版本9之前, HttpUrlConnection was unreliable. 也就是说, 使用volley时, 我们不需要关系网络请求是如何实现的, volley已经封装好了最好的选择方案, 保证了volley的稳定性.
- 所有的参数准备好之后, 才是真正的开始创建了一个RequestQueue, 调用它的start方法.
- 在start方法里, 我们可以看到new了一个CacheDispatcher缓存分发器和利用for循环默认new了4个NetworkDispatcher网络请求的分发器, CacheDispatcher和NetworkDispatcher继承了Thread类, 说明它们是一个线程.
- CacheDispatcher创建时传递了4个参数过去, 分别是一个在成员变量声明好的具有优先级的缓存请求队列CacheQueue,一个同样具有优先级的网络请求队列NetworkQueue, 一个之前创建好的磁盘缓存DiskBasedCache和一个ExecutorDelivery.
- 同样的NetworkDispatcher在创建时传递过去4个参数, 分别是一个网络请求队列, 一个网络请求, 一个磁盘缓存和一个ExecutorDelivery.
现在开始发送网络请求了
CacheDispatcher的run方法中, 首先就将DiskBasedCache进行初始化, 调用它的initialize方法判断当前缓存目录是否存在, 如果不存在, 则创建缓存目录然后return,如果存在缓存目录, 遍历所有的缓存文件, 读出所有缓存文件的头信息CacheHeader(包含key和过期时间等), 存入头的集合LinkedHashMap.
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);}
当发生网络请求时, 从集合中获取key, 这个key是请求类型+url组成的字符串, 通过key来获取缓存文件头信息保存到Cache.Entry里.
- 网络请求首先默认添加到mCacheQueue, CacheDispatcher会一直循环的查询mCacheQueue里有没有请求.
如果拿到了网络请求,便查询有没有缓存
Cache.Entry entry = mCache.get(request.getCacheKey());
如果没有缓存, 或者缓存已过期, 即”cache-miss”和”cache-hit-expired”, 直接将请求添加到网络请求队列中
mNetworkQueue.put(request);
如果entry不为null,并且缓存没有过期,即”cache-hit”, 就解析缓存网络请求的响应
Response<?> response = request.parseNetworkResponse( new NetworkResponse(entry.data, entry.responseHeaders)); 这个parseNetworkResponse方法的实现是交给Request的子类来完成的,因为不同种类的Request解析的方式也肯定不同。 自定义Request中,parseNetworkResponse()这个方法就是必须要重写的.
分发解析后的结果到主线程
mDelivery.postResponse(request, response);因为mDelivery是绑定到主线程的, 所以这个方法是如何在主线程运行的?public void postResponse(Request<?> request, Response<?> response, Runnable runnable) { request.markDelivered(); request.addMarker("post-response"); //传入了一个ResponseDeliveryRunnable对象,就可以保证该对象中的run()方法就是在主线程当中运行的了 mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable)); } 再看看ResponseDeliveryRunnable的run方法,// Deliver a normal response or error, depending. if (mResponse.isSuccess()) { mRequest.deliverResponse(mResponse.result); 这个就是我们在自定义Request时需要重写的另外一个方法,每一条网络请求的响应都是回调到这个方法中. } else { mRequest.deliverError(mResponse.error); }
加入到mNetworkQueue后
NetworkDispatcher里面也会一直循环的查询mNetworkQueue有没有请求
如果mNetworkQueue如果有请求,则执行网络请求NetworkResponse networkResponse = mNetwork.performRequest(request);
解析网络请求结果
Response<?> response = request.parseNetworkResponse(networkResponse);
将网络请求的结果存入缓存
mCache.put(request.getCacheKey(), response.cacheEntry);
将解析后的结果分发给主线程
mDelivery.postResponse(request, response);
1 0
- 总结volley源码解析
- 【Volley】Volley源码解析
- volley源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- Volley 源码解析
- android开发环境安装-Eclipse篇
- 手机访问 电脑虚拟机的服务器
- notifyDataSetChanged
- codeforces基础题——#362(div2)D
- Ubuntu 14.04LTS 触摸板无法使用
- 总结volley源码解析
- PAT(乙级)1018 人口普查(20)
- 第二周项目2 程序的多文件组织
- 《TCP/IP详解 卷1:协议》 读书笔记 第6章 ICMP:Internet控制报文协议
- notifyDataSetChanged() 动态更新ListView 通过 Handler AsyncTask两种方式
- Servlet生命周期及创建方式
- 项目1-C/C++语言中函数参数传递的三种方式
- Codeforces Round #317 [AimFund Thanks-Round] (Div. 2) C. Lengthening Sticks
- 第一行代码系列第二章——手动创建activity