Volley源码解析

Volley简介

Volley-是2013年Google I/O大会上推出的一个新的网络通信框架。

作为Google推出的一款Android端开源网络框架,了解其核心原理有便于我们更好的使用以及见解学习。

Volley的源码并不多,正好符合刚学会去看源码的人去读。以下为Volley的源码结构:

Volley源码结构


Volley的优缺点
  • 优点:

    1. 通信快,简单
    2. 支持所有的请求方式如GET|POST|PUT|DELETE|HEAD|OPTIONS|TRACE|PATCH
    3. 排序(对请求很多的情况下可以对多个网络请求进行优先级排序)
    4. 网络请求缓存
    5. 多级别取消请求
    6. 和Activity生命周期绑定(在Activity销毁时,可以同时取消网络请求)
  • 缺点:

    1. 不适合网络的上传和下载
    2. 最初的Volley是不支持https协议的请求,但后来升级改进后可以
    3. 由于Volley内部线程池默认使用了4个工作线程进行网络请求,所以它不适合高并发的网络请求
使用

Volley网络请求比较简单,以StringRequest作为请求举个🌰

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 1.创建请求队列
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
// 2.创建网络请求
StringRequest mStringReq = new StringRequest(Request.Method.GET, "http://www.imeina.cn/test/user/001",
new Response.Listener<String>(){
@Override
public void onResponse(String rep){
// 数据处理...
}
}, new Response.ErrorListener(){
@Override
public void onErrorResponse(VolleyError error){
// 请求失败处理...
}
}
);
// 3.将请求添加到请求队列中
mQueue.add(mStringReq);

JsonObjectRequest、JsonArrayRequest使用方式相同。

代码分析
  • Volley类中,newRequestQueue有2个重构方法

Volley.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public static RequestQueue newRequestQueue(Context context) {
return newRequestQueue(context, (BaseHttpStack) null);
}
/**
* @params stack HurlStack|HttpClientStack
* 分别使用HttpURLConnection、HttpClient作为网络请求方式
*/
public static RequestQueue newRequestQueue(Context context, BaseHttpStack stack) {
BasicNetwork network;
if(stack == null){
...
// 实例化BasicNetwork
network = new BasicNetwork(new HurlStack());
...
}else{
// 使用用户传入的BaseHttpStack实例化BasicNetwork
network = new BasicNetwork(stac);
}
return newRequestQueue(context, network);
}
private static RequestQueue newRequestQueue(Context context, Network network) {
// 通过cacheDir和network作为参数构造RequestQueue返回
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
// ⚠️注意这里:在未向请求队列添加请求前便开启了网络请求线程来等待处理,所以只要使用RequestQueue.add()后,请求就执行了
queue.start();
return queue;
}

  • RequestQueue作为请求队列,内部封装了许多属性,例如:NetworkDispatcher[] mDispatchers, CacheDispatcher mCacheDispatcher, 以及一些回调监听。
    其中有一个很重要的常量 DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;它是Volley线程池设置的默认工作线程数。所以Volley不适合请求量大的并发处理,高并发的网络请求会排队延迟。
    RequestQueue中提供了start()和stop()方法用于开启网络请求执行和停止取消执行,其内部实质调用的mCacheDispatcher和networkDispatcher线程进行的处理。

RequestQueue.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
...
private final Cache mCache;
private final Network mNetwork;
/** 用于执行缓存的调度线程 */
private CacheDispatcher mCacheDispatcher;
/** 执行网络请求回调监听 */
private final List<RequestFinishedListener> mFinishedListeners = new ArrayList<>();
/** 默认网络请求线程池大小为4 */
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
/** 响应交付用于子线程中将数据回调到主线程 */
private final ResponseDelivery mDelivery;
/** 用于执行网络请求的调度线程 */
private final NetworkDispatcher[] mDispatchers;
public RequestQueue(
Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) {
mCache = cache;
mNetwork = network;
mDispatchers = new NetworkDispatcher[threadPoolSize];
mDelivery = delivery;
}
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(
cache,
network,
threadPoolSize,
// ⚠️注意这里:创建ExecutorDelivery并使用主线程中的Looper作为参数构造Handler
new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}
/**
* 执行请求分发,该方法无须手动调用,在使用Volley.newRequestQueue()返回RequestQueue前已经被执行
*/
public void start() {
stop(); // Make sure any currently running dispatchers are stopped.
// Create the cache dispatcher and start it.
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
// 执行缓存请求
mCacheDispatcher.start();
// Create network dispatchers (and corresponding threads) up to the pool size.
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher =
new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
// 执行网络请求
networkDispatcher.start();
}
}
/**
* 中断网络请求
*/
public void stop() {
if (mCacheDispatcher != null) {
// 中断缓存请求
mCacheDispatcher.quit();
}
for (final NetworkDispatcher mDispatcher : mDispatchers) {
if (mDispatcher != null) {
// 中断网络请求
mDispatcher.quit();
}
}
}
/**
* 添加网络请求到请求队列中
*/
public <T> Request<T> add(Request<T> request) {
// 为当前请求设置tag(绑定为当前请求队列)
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 (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
mCacheQueue.add(request);
return request;
}

  • NetworkDispatcher作为工作线程,在其内部维护了一个阻塞队列mQueue,在run()方法中轮询。
    在使用Network执行请求返回数据后通过mDelivery对象将数据结果返回到UI线程中。

NetworkDispatcher.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class NetworkDispatcher extends Thread {
/** 阻塞请求队列 */
private final BlockingQueue<Request<?>> mQueue;
private final Network mNetwork;
private final Cache mCache;
private final ResponseDelivery mDelivery;
private volatile boolean mQuit = false;
/** 退出中断线程 */
public void quit() {
mQuit = true;
interrupt();
}
@Override
public void run() {
//NetworkDispatcher将当前线程优先级设置为后台线程,并执行请求
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
while (true) {
try {
processRequest();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
//如果请求发生异常且mQuit为true则强制当前线程中断
Thread.currentThread().interrupt();
return;
}
VolleyLog.e(
"Ignoring spurious interrupt of NetworkDispatcher thread; "
+ "use quit() to terminate it");
}
}
}
/**
*执行网络请求
*/
void processRequest(Request<?> request) {
long startTimeMs = SystemClock.elapsedRealtime();
...
// Perform the network request.
NetworkResponse networkResponse = mNetwork.performRequest(request);
...
// 通过mDelivery将请求信息以及响应数据传递到主线程
request.markDelivered();
mDelivery.postResponse(request, response);
request.notifyListenerResponseReceived(response);
}
}

  • ExecutorDelivery是ResponseDelivery接口的子类,它通过Executor调度,使用handler去将ResponseDeliveryRunnable放到UI线程去执行最终完成了线程间的数据传递。
    具体是ResponseDeliveryRunnable内部通过我们最先创建的request对象调用其deliverResponse()和deliverError()方法将数据回调。

ExecutorDelivery.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public ExecutorDelivery(final Handler handler) {
// Make an Executor that just wraps the handler.
mResponsePoster =
new Executor() {
@Override
public void execute(Runnable command) {
// 通过handler将ResponseDeliveryRunnable扔到UI线程执行
handler.post(command);
}
};
}
@Override
public void postResponse(Request<?> request, Response<?> response) {
postResponse(request, response, null);
}
@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
request.markDelivered();
request.addMarker("post-response");
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
}
@SuppressWarnings("rawtypes")
private static class ResponseDeliveryRunnable implements Runnable {
private final Request mRequest;
private final Response mResponse;
private final Runnable mRunnable;
public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {
mRequest = request;
mResponse = response;
mRunnable = runnable;
}
@SuppressWarnings("unchecked")
@Override
public void run() {
// If this request has canceled, finish it and don't deliver.
if (mRequest.isCanceled()) {
mRequest.finish("canceled-at-delivery");
return;
}
// Deliver a normal response or error, depending.
if (mResponse.isSuccess()) {
// Request具体实现类使用Response.Listener进行回调
mRequest.deliverResponse(mResponse.result);
} else {
// Request具体实现类使用Response.ErroListener进行回调
mRequest.deliverError(mResponse.error);
}
// If this is an intermediate response, add a marker, otherwise we're done
// and the request can be finished.
if (mResponse.intermediate) {
mRequest.addMarker("intermediate-response");
} else {
mRequest.finish("done");
}
// If we have been provided a post-delivery runnable, run it.
if (mRunnable != null) {
mRunnable.run();
}
}
}

总结
  1. Volley在主线程中创建一个request请求后,就会将该请求放到队列中,然后后台线程(NetWorkDispatcher)从队列中取出请求,调用网络相关类,执行请求,得到返回结果后,通过ExecutorDelivery将一个Runnable对象放到UI线程的消息池里去执行。
  2. 在创建Request的时候,需要制定Response.Listener,Response.ErroListener对象,因为在Request执行完后,Volley会通过handler机制,将在UI线程里调用这些listener的相关方法,从而使应用可以在这些listener的相关方法里,获得这些请求结果数据,从而实现刷新UI等操作。
如果帮到了你,想打赏支持,喏~