

Android:Volley源码解析
source link: http://www.androidchina.net/2965.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

简单实例
Volley是一个封装HttpUrlConnection和HttpClient的网络通信框架,集AsyncHttpClient和Universal-Image-Loader的优点于了一身,既可以像AsyncHttpClient一样非常简单地进行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开发中文站 » Android:Volley源码解析
Recommend
-
26
-
9
README.md Volley Volley is an HTTP library that makes networking for Android apps easier and, most importantly, faster. For more infor...
-
7
转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/47721631; 本文出自:【张鸿洋...
-
6
Android利用Volley异步加载数据(JSON和图片)完整示例 – Android开发中文站MainActivity如下: package androidchina.net.testvolley;import org.json.JSONObject;
-
7
是时候用NoHttp来替换Volley了 – Android开发中文站你的位置:Android开发中文站 > Android开发 >
-
7
Volley February 10, 2016 Open source community has been a great help for me to learn new stuff. Be it the software development process or coding stand...
-
6
Android网络请求(4) 网络请求框架Volley Volley是Google在2013年5月15日到17日在旧金山Moscone中心举办网络开发者年会中推出的Android异步网络加载框架和图片加载框架,它特别适合数据体量小且通讯频繁的网络操作...
-
5
The fastest way to monetize your expertise
-
5
Introduction Volley is an HTTP library that makes networking for Android apps easier and most importantly, faster. It is available on GitHub. In this article...
-
7
Android Volley 基本使用 本篇主要介绍 Google 给Android 平台提供的 Volley 一个 Http请求库 , 齐射! Volley是Google 提供的一个小巧的异步请求库,扩展很强支持okhttp,(默认是 An...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK