Android:Volley源代码解析
简单实例
Volley是一个封装HttpUrlConnection和HttpClient的网络通信框架,集AsyncHttpClient和Universal-Image-Loader的长处于了一身。既能够像AsyncHttpClient一样很easy地进行HTTP通信,也能够像Universal-Image-Loader一样轻松载入并缓存下载的图片。Volley在性能方面也进行了大幅度的调整,它的设计目标就是进行数据量不大,但通信频繁的网络操作
,而对于大数据量的网络操作,比方说下载文件等,Volley的表现就会比較糟糕。从以下这个简单的实例来研究一下源代码。
RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);
StringRequest stringRequest = new StringRequest("http://www.baidu.com", new Response.Listener<String>() {
@Override
public void onResponse(String s) {
tv.setText(s);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
}
});
mQueue.add(stringRequest);
流程
1、以静态工厂形式实例化一个RequestQueue对象
RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);
- 首先看一下RequestQueue这个类:
public class RequestQueue {
private AtomicInteger mSequenceGenerator;
private final Map<String, Queue<Request>> mWaitingRequests;
private final Set<Request> mCurrentRequests;
private final PriorityBlockingQueue<Request> mCacheQueue;
private final PriorityBlockingQueue<Request> mNetworkQueue;
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
private final Cache mCache;
private final Network mNetwork;
private final ResponseDelivery mDelivery;
private NetworkDispatcher[] mDispatchers;
private CacheDispatcher mCacheDispatcher;
public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) {
this.mSequenceGenerator = new AtomicInteger();
this.mWaitingRequests = new HashMap();
this.mCurrentRequests = new HashSet();
this.mCacheQueue = new PriorityBlockingQueue();
this.mNetworkQueue = new PriorityBlockingQueue();
this.mCache = cache;
this.mNetwork = network;
this.mDispatchers = new NetworkDispatcher[threadPoolSize];
this.mDelivery = delivery;
}
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}
public RequestQueue(Cache cache, Network network) {
this(cache, network, 4);
}
...
}
从构造函数可知,mWaitingRequests、mCurrentRequests、mCacheQueue、mNetworkQueue是以组合形式实例化,后两者是堵塞队列;而mCache、mNetwork是以聚合形式注入;mDelivery默认也是组合形式new ExecutorDelivery(new Handler(Looper.getMainLooper())))
实例化。
- newRequestQueue方法:
public static RequestQueue newRequestQueue(Context context) {
return newRequestQueue(context, (HttpStack)null);
}
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
File cacheDir = new File(context.getCacheDir(), "volley");
String userAgent = "volley/0";
try {
String network = context.getPackageName();
PackageInfo queue = context.getPackageManager().getPackageInfo(network, 0);
userAgent = network + "/" + queue.versionCode;
} catch (NameNotFoundException var6) {
;
}
if(stack == null) {
if(VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
BasicNetwork network1 = new BasicNetwork((HttpStack)stack);
RequestQueue queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1);
queue1.start();
return queue1;
}
结合RequestQueue类可知,实例化的RequestQueue对象,注入了new DiskBasedCache(cacheDir)
和network1
。缓存方式默认是磁盘缓存。NetWork对象会依据系统版本号。选用不同的Http通信方式。
- queue.start()方法
public void start() {
this.stop();
this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
this.mCacheDispatcher.start();
for(int i = 0; i < this.mDispatchers.length; ++i) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);
this.mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
CacheDispatcher和NetworkDispatcher都是继承Thread类。所以这种方法生成一条缓存分发线程,和四条网络线程。
- CacheDispatcher类继承Thread类。全部參数都是聚合形式注入,看下关键的run()方法。因为代码较长。这里不贴了,分段分析下几个比較重要的方法
while(true){
...
Request e = (Request)this.mCacheQueue.take();
...
}
首先任务是一个死循环,因为mCacheQueue是个堵塞队列,所以将不断地从堵塞队列读取Request
Entry entry = this.mCache.get(e.getCacheKey());
if(entry == null) {
e.addMarker("cache-miss");
this.mNetworkQueue.put(e);
} else if(entry.isExpired()) {
e.addMarker("cache-hit-expired");
e.setCacheEntry(entry);
this.mNetworkQueue.put(e);
} else {
e.addMarker("cache-hit");
Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
...
}
推断请求是否有缓存。假设没有或者缓存已经过期。将请求放到网络队列里面
。否则找到缓存。则进行以下的操作。
Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
parseNetworkResponse是Request类的抽象方法,我们进去StringRequest看下:
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException var4) {
parsed = new String(response.data);
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
可看作是对网络下载的数据进行解析处理。然后返回。
this.mDelivery.postResponse(e, response);
最后进行这一步,mDelivery是在RequestQueue里面实例化后注入CacheDispatcher的。详细的实例化对象:new ExecutorDelivery(new Handler(Looper.getMainLooper()))。看下ExecutorDelivery类。找到postResponse方法。
public void postResponse(Request<?> request, Response<?> response) {
this.postResponse(request, response, (Runnable)null);
}
public void postResponse(Request<?
> request, Response<?
> response, Runnable runnable) {
...
this.mResponsePoster.execute(new ExecutorDelivery.ResponseDeliveryRunnable(request, response, runnable));
}
继续往下看
private class ResponseDeliveryRunnable implements Runnable {
...
run(){
...
if(this.mResponse.isSuccess()) {
this.mRequest.deliverResponse(this.mResponse.result);
}
...
}
...
}
deliverResponse方法相同是Request类的抽象方法,我们进去StringRequest看下
protected void deliverResponse(String response) {
this.mListener.onResponse(response);
}
就一句回调
- NetworkDispatcher类相同继承Thread类,其分析过程和CacheDispatcher差点儿相同,重要的相同是以下几步:
1、从网络堵塞队列读取请求,request = (Request)this.mQueue.take();
2、网络下载,NetworkResponse e = this.mNetwork.performRequest(request);(假设是CacheDispatcher这一步就是缓存推断)
3、处理下载后的数据,Response response = request.parseNetworkResponse(e);
3、对处理后的数据进行回调,this.mDelivery.postResponse(e, response)。
2、实例化一个Request对象
StringRequest stringRequest = new StringRequest (url,listener,errorListener);
public class StringRequest extends Request<String> {
private final Listener<String> mListener;
public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {
super(method, url, errorListener);
this.mListener = listener;
}
public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
this(0, url, listener, errorListener);
}
protected void deliverResponse(String response) {
this.mListener.onResponse(response);
}
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException var4) {
parsed = new String(response.data);
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
}
由第一个分析步骤能够知道,这个Request主要就是进行两个操作,也就是重写两个方法。
protected abstract Response<T> parseNetworkResponse(NetworkResponse var1);
对下载后的数据进行解析处理。protected abstract void deliverResponse(T var1);
最后回调操作这个数据的方法。
所以构造函数仅需下载地址和回调操作的方法。
3、调用queue.add()方法
if(!request.shouldCache()) {
this.mNetworkQueue.add(request);
return request;
}
假设不须要缓存就直接加入到网络队列里面,Request有个比較重要的布尔字段mShouldCache,默认是用来推断是否要进行磁盘缓存的。
this.mCacheQueue.add(request);
否则将其加入到缓存队列,这种方法上面也会进行一些当前队列和等待队列的防反复的操作。
小结
框架部分:
1、实例化一个RequestQueue对象,开启一条缓存线程和默认的四条网络线程,线程不断地从缓存堵塞队列和网络堵塞队列里面读取请求;
2、假设缓存线程从缓存队列里面读取的请求已经缓存过,则解析数据回调操作方法。否则将其加入到网络队列;
3、假设缓存线程从缓存队列里面读取的请求没有缓存过,则加入到网络队列。
4、网络线程从网络堵塞队列不断读取请求,读到请求后则由封装好的HttpStack对象进行网络下载处理、下载后回调对数据处理的方法,处理后回调操作数据的方法。
客户部分:
1、实例化一个请求对象。在请求对象里面重写处理网络下载后的数据的方法。和操作处理后的数据的方法。
2、将请求对象加入到请求队列。请求须要缓存则会被加入到分配到缓存队列,不须要则被加入到网络队列。
之前看过一个问题。说框架和库有什么不同,高人答曰:框架是他调用你代码,库是你调用他代码。
优秀的框架拓展性是如此之强,尽管自己远没那个能力,只是也算开了眼界!
Android:Volley源代码解析的更多相关文章
- [转] Android Volley完全解析(一),初识Volley的基本用法
版权声明:本文出自郭霖的博客,转载必须注明出处. 目录(?)[-] Volley简介 下载Volley StringRequest的用法 JsonRequest的用法 转载请注明出处:http ...
- Android Volley完全解析
1. Volley简介 我们平时在开发Android应用的时候不可避免地都需要用到网络技术,而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据.Android系统中主要提供了两种方式来进行H ...
- Android xUtils3源代码解析之网络模块
本文已授权微信公众号<非著名程序猿>原创首发,转载请务必注明出处. xUtils3源代码解析系列 一. Android xUtils3源代码解析之网络模块 二. Android xUtil ...
- Android Volley完全解析(三),定制自己的Request
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17612763 经过前面两篇文章的学习,我们已经掌握了Volley各种Request ...
- Android Volley完全解析(二),使用Volley加载网络图片
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17482165 在上一篇文章中,我们了解了Volley到底是什么,以及它的基本用法. ...
- Android Volley全然解析(四),带你从源代码的角度理解Volley
版权声明:本文出自郭霖的博客,转载必须注明出处. https://blog.csdn.net/sinyu890807/article/details/17656437 转载请注明出处:http://b ...
- volley源代码解析(七)--终于目的之Response<T>
在上篇文章中,我们终于通过网络,获取到了HttpResponse对象 HttpResponse是android包里面的一个类.然后为了更高的扩展性,我们在BasicNetwork类里面看到.Volle ...
- [转]Android Volley完全解析(四),带你从源码的角度理解Volley
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17656437 经过前三篇文章的学习,Volley的用法我们已经掌握的差不多了,但是 ...
- Android EventBus源代码解析 带你深入理解EventBus
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:[张鸿洋的博客] 上一篇带大家初步了解了EventBus ...
- Android DiskLruCache 源代码解析 硬盘缓存的绝佳方案
转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/47251585: 本文出自:[张鸿洋的博客] 一.概述 依然是整理东西.所以最近 ...
随机推荐
- 【Java学习】调用ByteBuffer.getInt()方法得到808464432
调用ByteBuffer.getInt()方法遇到的奇怪错误 最近在参加阿里的中间件比赛,中间用到了RocketMQ的思想,并且主要集中在使用NIO来读写文件.其中遇到了一个很蛋疼的问题,想了半天想不 ...
- javascript中Date对象的应用
前面的话 简易日历作为javascript中Date对象的常见应用,用途较广泛.本文将详细说明简易日历的实现思路 效果演示 HTML说明 使用type=number的两个input分别作为年和月的输入 ...
- PHP视频教程 字符串处理函数(三)
字符串替换函数: str_replace() 替换字符串或数组元素,区分大小,第四个参数可选用于统计替换次数. str_ireplace() 不区分大小写替换 字符串函数比较 strcmp()比较字符 ...
- 可以在GitHub或者码云里 直接搜索 项目 比如 哔哩哔哩
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha Search · 哔哩哔哩 哔哩哔哩 · 搜索 - 码云 还有就是 以前的项目 可以不要 ...
- Palindromic Tree 回文自动机-回文树 例题+讲解
回文树,也叫回文自动机,是2014年被西伯利亚民族发明的,其功能如下: 1.求前缀字符串中的本质不同的回文串种类 2.求每个本质不同回文串的个数 3.以下标i为结尾的回文串个数/种类 4.每个本质不同 ...
- UVA11468 Substring --- AC自动机 + 概率DP
UVA11468 Substring 题目描述: 给定一些子串T1...Tn 每次随机选择一个字符(概率会给出) 构造一个长为n的串S,求T1...Tn不是S的子串的概率 直接把T1...Tn建成AC ...
- [SDOI2017]数字表格 --- 套路反演
[SDOI2017]数字表格 由于使用markdown的关系 我无法很好的掌控格式,见谅 对于这么简单的一道题竟然能在洛谷混到黑,我感到无语 \[\begin{align*} \prod\limits ...
- Djangio笔记
django图解 新创建一个项目后的目录层级
- hihocoder155周 任务分配
时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定 N 项任务的起至时间( S1, E1 ), ( S2, E2 ), ..., ( SN, EN ), 计算最少需要多 ...
- Swify闭包
闭包:是字包含的匿名函数代码块,可以做为表达式.函数参数和函数返回值,闭包表达式的运算结果是一种函数类型.类似于 C# Lambda 表达式. 闭包表达式: {(参数列表)->返回类型 in 语 ...