Volley源码解析

  1. 1. 使用
    1. 1.1. StringRequest
    2. 1.2. 流程
    3. 1.3. Post请求
    4. 1.4. Http Header
    5. 1.5. JsonRequest
    6. 1.6. ImageRequest
  2. 2. 源码
    1. 2.1. RequestQueue
      1. 2.1.1. NetworkDispatcher
        1. 2.1.1.1. Network.performRequest
          1. 2.1.1.1.1. HurlStack.performRequest
          2. 2.1.1.1.2. HttpClientStack.performRequest
        2. 2.1.1.2. Request.parseNetworkResponse
        3. 2.1.1.3. ResponseDelivery.postResponse
      2. 2.1.2. CacheDispatcher
    2. 2.2. StringRequest
    3. 2.3. RequestQueue
  3. 3. 总结
    1. 3.1. 总体框架流程图
    2. 3.2. Volley.newRequestQueue(context)
    3. 3.3. NetworkDispatcher流程图
    4. 3.4. CacheDispatcher流程图
    5. 3.5. ResponseDelivery流程图
    6. 3.6. RequestQueue.add(request)
  4. 4. 参考

在2013年 Google I/O 大会上推出了一个网络通信框架 —— Volley ,基于 Android 系统中主要提供了两种方式来进行 HTTP 通信,HttpURLConnection 和 HttpClient (Android M 之后已经删除了 HttpClient )。

使用

Volley的用法非常简单。

StringRequest

1
RequestQueue queue = Volley.newRequestQueue(context);

这里拿到的 RequestQueue 是一个请求队列对象,它可以缓存所有的HTTP请求,然后按照一定的算法并发地发出这些请求。

1
2
3
4
5
6
7
8
9
10
StringRequest stringRequest = new StringRequest("http://yydcdut.com",  
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});

StringRequest 的构造函数需要传入三个参数,第一个参数就是目标服务器的 URL 地址,第二个参数是服务器响应成功的回调,第三个参数是服务器响应失败的回调

1
queue.add(stringRequest);

将这个 StringRequest 对象添加到 RequestQueue

同时注意,要访问网络需要访问网络的权限:

1
<uses-permission android:name="android.permission.INTERNET" />

如果还设置了缓存到 SD 卡上的话,还要加 SD 卡的读写权限。

流程

  1. 创建一个RequestQueue对象。
  2. 创建一个StringRequest对象。
  3. 将StringRequest对象添加到RequestQueue里面。

Post请求

1
2
3
4
5
6
7
8
9
StringRequest stringRequest = new StringRequest(Method.POST, url,  listener, errorListener) {  
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> map = new HashMap<String, String>();
map.put("params1", "value1");
map.put("params2", "value2");
return map;
}
};

Http Header

1
2
3
4
5
6
7
8
9
StringRequest stringRequest = new StringRequest(Method.POST, url,  listener, errorListener) {  
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> map = new HashMap<String, String>();
map.put("header1", "value1");
map.put("header2", "value2");
return map;
}
};

JsonRequest

类似于 StringRequestJsonRequest 也是继承自 Request ,但是一个抽象类,有两个直接的子类,JsonObjectRequestJsonArrayRequest

1
2
3
4
5
6
7
8
9
10
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest("url", null,  
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});

ImageRequest

1
2
3
4
5
6
7
8
9
10
11
12
ImageRequest imageRequest = new ImageRequest("http://yydcdut.com/img/avatar.png",  
new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
imageView.setImageBitmap(response);
}
}, 0, 0, Config.RGB_565, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
imageView.setImageResource(R.drawable.default_image);
}
});

ImageRequest 的构造函数接收六个参数,第一个参数就是图片的URL地址。第二个参数是图片请求成功的回调。第三第四个参数分别用于指定允许图片最大的宽度和高度,如果指定的网络图片的宽度或高度大于这里的最大值,则会对图片进行压缩,指定成0的话就表示不管图片有多大,都不会进行压缩。第五个参数用于指定图片的颜色属性,Bitmap.Config 下的几个常量都可以在这里使用。第六个参数是图片请求失败的回调

源码

源码的讲解还是按照上文使用的流程来分析。

RequestQueue

Volley.newRequestQueue(context); 开始:

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
private static final String DEFAULT_CACHE_DIR = "volley";

public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
//Volley 会将请求头中的 User-Agent 字段设置为 App 的 {packageName}/{versionCode},如果异常则使用 "volley/0"
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException e) {
}

if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}

Network network = new BasicNetwork(stack);

RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();

return queue;
}


public static RequestQueue newRequestQueue(Context context) {
return newRequestQueue(context, null);
}

在判断 HttpStack 是否为空的时候进行了 Android 版本的判断,如果大于等于9,则使用 HurlStack ,否则使用 HttpClientStack ,两者均继承于接口 HttpStack ,但 HurlStack 的实现是基于 HttpUrlConnection 的,HttpClientStack 的实现是基于 HttpClient 的,之所以在这里进行了版本判断,是因为在小于9的 Android 版本中,HttpUrlConnection 存在着一些 bug,比如对一个可读的 InputStream 调用 close() 方法时,就有可能会导致连接池失效了。但是在 Android 2.3 版本之后,HttpUrlConnection 进行了很大的修正和优化,比如默认 GZip 、Https 方面的改进、增加缓存机制等。

创建好了 HttpStack 之后,接下来又创建了一个 Network 对象,它是用于根据传入的 HttpStack 对象来处理网络请求的,紧接着 new 出一个 RequestQueue 对象,并调用它的 start()方法进行启动,然后将 RequestQueue 返回。

那么分别来看看 BasicNetworkRequestQueue 、和 queue.start(); 做了那些事:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class BasicNetwork implements Network {

private static int DEFAULT_POOL_SIZE = 4096;

protected final HttpStack mHttpStack;

protected final ByteArrayPool mPool;

public BasicNetwork(HttpStack httpStack) {
this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));
}

public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) {
mHttpStack = httpStack;
mPool = pool;
}

// blablabla......
}

BasicNetwork 中有一个 byte[] 复用池。目的在于不要频繁创建生命周期比较短的 byte[] 对象会使堆频繁分配位置以及在 Android 垃圾回收导致的延时。

Simply creating and disposing such buffers in the conventional manner can considerable heap churn and garbage collection delays on Android, which lacks good management of short-lived heap objects. It may be advantageous to trade off some memory in the form of a permanently allocated pool of buffers in order to gain heap performance improvements.

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
public class RequestQueue {

/** Number of network request dispatcher threads to start. */
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;

/** Cache interface for retrieving and storing respones. */
private final Cache mCache;

/** Network interface for performing requests. */
private final Network mNetwork;

/** Response delivery mechanism. */
private final ResponseDelivery mDelivery;

/** The network dispatchers. */
private 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,
new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}

public RequestQueue(Cache cache, Network network) {
this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
}

//blablabla......
}

cache 传入的是 DiskBasedCache ,继承 Cache 类,基于 Disk 的缓存实现类。 ExecutorDelivery 为请求结果传输类,其父类为 ResponseDelivery,在 Handler 对应线程中传输缓存调度线程或者网络调度线程中产生的请求结果或请求错误,会在请求成功的情况下调用 Request.deliverResponse() 函数,失败时调用 Request.deliverError() 函数。NetworkDispatcher 继承于 Thread ,用于调度处理请求。启动后会不断从网络请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给 ResponseDelivery ,去执行后续处理,并判断结果是否要进行缓存。

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
public class RequestQueue {

/** The queue of requests that are actually going out to the network. */
private final PriorityBlockingQueue<Request> mNetworkQueue =
new PriorityBlockingQueue<Request>();

public void start() {
stop(); // 停止所有dispatchers
// 创建cache dispatcher并启动
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();

// 创建 network dispatchers
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 (int i = 0; i < mDispatchers.length; i++) {
if (mDispatchers[i] != null) {
mDispatchers[i].quit();
}
}
}
}

CacheDispatcherNetworkDispatcher 均继承于 Thread ,那么一旦 Volley.newRequestQueue(context); 开始,就有五个线程再后台运行着,而 CacheDispatcher 是缓存线程,NetworkDispatcher 是网络访问线程。

查看 Volley.newRequestQueue(context) 图

NetworkDispatcher

那么我们先来看看 NetworkDispatcher :

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
public class NetworkDispatcher extends Thread {
/** The queue of requests to service. */
private final BlockingQueue<Request> mQueue;
/** The network interface for processing requests. */
private final Network mNetwork;
/** The cache to write to. */
private final Cache mCache;
/** For posting responses and errors. */
private final ResponseDelivery mDelivery;
/** Used for telling us to die. */
private volatile boolean mQuit = false;

public NetworkDispatcher(BlockingQueue<Request> queue,
Network network, Cache cache,
ResponseDelivery delivery)
{

mQueue = queue;
mNetwork = network;
mCache = cache;
mDelivery = delivery;
}

public void quit() {
mQuit = true;
interrupt();
}

@Override
public void run() {
//设置线程优先级为后台,这样当多个线程并发后很多无关紧要的线程分配的CPU时间将会减少,有利于主线程的处理
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Request request;
while (true) {
try {
//从queue中取出request,因为mQueue是BlockingQueue,那么当队列中没有数据的时候会一直阻塞在这里
request = mQueue.take();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
}

try {
request.addMarker("network-queue-take");//用于log

if (request.isCanceled()) {
request.finish("network-discard-cancelled");//从requestQueue中移除,然后log
continue;
}

//流量统计
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
}

//走网络访问,然后返回networkResponse
NetworkResponse networkResponse = mNetwork.performRequest(request);
request.addMarker("network-http-complete");//用于log

//如果服务器返回304并且我们已经访问过了,结束
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
continue;
}

//把networkResponse解析成response
Response<?> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete");//用于log

//判断建立的request中是否需要缓存,默认开启,同时response.cacheEntry的实际内容是返回的header中的Cache-Control参数信息
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");//用于log
}

//标记已经发送过了
request.markDelivered();
//传递结构出去
mDelivery.postResponse(request, response);
} catch (VolleyError volleyError) {
parseAndDeliverNetworkError(request, volleyError);
} catch (Exception e) {
VolleyLog.e(e, "Unhandled exception %s", e.toString());
mDelivery.postError(request, new VolleyError(e));
}
}
}

private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {
error = request.parseNetworkError(error);
mDelivery.postError(request, error);
}
}

实际上走网络访问请求还是在 Network.performRequest 中进行的,网络访问请求完成之后会返回 NetworkResponse ,再通过 Request.parseNetworkResponse 解析成 Response ,再将 RequestResponse 通过 Delivery.postResponse 传递出去。

所以这里的流程是:

  1. mQueue 中获取 Request,没有数据一直堵塞在那
  2. 拿到 Request 之后通过 Network.performRequest 进行网络访问,返回 NetworkResponse
  3. 如果状态码是304则不继续下面操作
  4. 通过 Request.parseNetworkResponseNetworkResponse 解析成 Response
  5. Delivery.postResponseRequestResponse 传递出去

查看 NetworkDispatcher 流程图

Network.performRequest

那么再来看一下访问网络的 BasicNetwork:

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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
public class BasicNetwork implements Network {
@Override
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();//开始时间
while (true) {
HttpResponse httpResponse = null;
byte[] responseContents = null;
Map<String, String> responseHeaders = new HashMap<String, String>();
try {
// Gather headers.
Map<String, String> headers = new HashMap<String, String>();
//加入缓存信息的header
addCacheHeaders(headers, request.getCacheEntry());
//httpStack走请求网络访问
httpResponse = mHttpStack.performRequest(request, headers);
//得到http code
StatusLine statusLine = httpResponse.getStatusLine();
int statusCode = statusLine.getStatusCode();

//将header[] 转成 map 形式
responseHeaders = convertHeaders(httpResponse.getAllHeaders());
// 304
if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
//直接返回304的NetworkResponse
return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,
request.getCacheEntry().data, responseHeaders, true);
}

// 像204这种可能没有返回内容,需要判断一下
if (httpResponse.getEntity() != null) {
//将entity内容转换成byte[]
responseContents = entityToBytes(httpResponse.getEntity());
} else {
//如果是没有内容的,就返回byte[0]
responseContents = new byte[0];
}

//判断时间,如果花费事件很长的话,log出来
long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
logSlowRequests(requestLifetime, request, responseContents, statusLine);
//小于200或者大于299的抛出异常
if (statusCode < 200 || statusCode > 299) {
throw new IOException();
}
return new NetworkResponse(statusCode, responseContents, responseHeaders, false);
} catch (SocketTimeoutException e) {
attemptRetryOnException("socket", request, new TimeoutError());
} catch (ConnectTimeoutException e) {
attemptRetryOnException("connection", request, new TimeoutError());
} catch (MalformedURLException e) {
throw new RuntimeException("Bad URL " + request.getUrl(), e);
} catch (IOException e) {
int statusCode = 0;
NetworkResponse networkResponse = null;
if (httpResponse != null) {
statusCode = httpResponse.getStatusLine().getStatusCode();
} else {
throw new NoConnectionError(e);
}
VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
if (responseContents != null) {
networkResponse = new NetworkResponse(statusCode, responseContents,
responseHeaders, false);
if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
statusCode == HttpStatus.SC_FORBIDDEN) {
attemptRetryOnException("auth",
request, new AuthFailureError(networkResponse));
} else {
// TODO: Only throw ServerError for 5xx status codes.
throw new ServerError(networkResponse);
}
} else {
throw new NetworkError(networkResponse);
}
}
}
}

private void addCacheHeaders(Map<String, String> headers, Cache.Entry entry) {
// If there's no cache entry, we're done.
if (entry == null) {
return;
}

if (entry.etag != null) {
headers.put("If-None-Match", entry.etag);
}

if (entry.serverDate > 0) {
Date refTime = new Date(entry.serverDate);
headers.put("If-Modified-Since", DateUtils.formatDate(refTime));
}
}

private static Map<String, String> convertHeaders(Header[] headers) {
Map<String, String> result = new HashMap<String, String>();
for (int i = 0; i < headers.length; i++) {
result.put(headers[i].getName(), headers[i].getValue());
}
return result;
}

private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError {
//结合了ByteArrayPool复用池的ByteArrayOutputStream
PoolingByteArrayOutputStream bytes =
new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength());
byte[] buffer = null;
try {
InputStream in = entity.getContent();
if (in == null) {
throw new ServerError();
}
buffer = mPool.getBuf(1024);
int count;
while ((count = in.read(buffer)) != -1) {
bytes.write(buffer, 0, count);
}
return bytes.toByteArray();
} finally {
try {
entity.consumeContent();
} catch (IOException e) {
VolleyLog.v("Error occured when calling consumingContent");
}
mPool.returnBuf(buffer);
bytes.close();
}
}
}

BasicNetwork 中真正走网络访问的实际上是 mHttpStack.performRequest() ,而 mHttpStack 这里是接口,面对抽象编程,在 Volley 中实现是 HurlStackHttpClientStack ,那么来看一下这两个类中对方法 performRequest() 的实现:

HurlStack.performRequest
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
public class HurlStack implements HttpStack {
@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError {
//得到url
String url = request.getUrl();
//准备header
HashMap<String, String> map = new HashMap<String, String>();
map.putAll(request.getHeaders());
map.putAll(additionalHeaders);
//UrlRewriter是一个接口,request中的mUrl属性是final,UrlRewriter通过hUrlStack的构造函数中传入,UrlRewriter.rewriteUrl(originalUrl),通过这个方法进行对原始url判断是否进行更换
if (mUrlRewriter != null) {
String rewritten = mUrlRewriter.rewriteUrl(url);
if (rewritten == null) {
throw new IOException("URL blocked by rewriter: " + url);
}
url = rewritten;
}
//HttpUrlConnection的流程
URL parsedUrl = new URL(url);
HttpURLConnection connection = openConnection(parsedUrl, request);
for (String headerName : map.keySet()) {
connection.addRequestProperty(headerName, map.get(headerName));
}
//设置Post还是Get等
setConnectionParametersForRequest(connection, request);
// http1.1
ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
int responseCode = connection.getResponseCode();
if (responseCode == -1) {
throw new IOException("Could not retrieve response code from HttpUrlConnection.");
}
StatusLine responseStatus = new BasicStatusLine(protocolVersion,
connection.getResponseCode(), connection.getResponseMessage());
BasicHttpResponse response = new BasicHttpResponse(responseStatus);
//得到服务器返回的数据,并设置到response中
response.setEntity(entityFromConnection(connection));
//设置header
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
if (header.getKey() != null) {
Header h = new BasicHeader(header.getKey(), header.getValue().get(0));
response.addHeader(h);
}
}
return response;
}

static void setConnectionParametersForRequest(HttpURLConnection connection, Request<?> request) throws IOException, AuthFailureError {
switch (request.getMethod()) {
case Method.DEPRECATED_GET_OR_POST:
//设置要发送的数据
byte[] postBody = request.getPostBody();
if (postBody != null) {
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.addRequestProperty(HEADER_CONTENT_TYPE,
request.getPostBodyContentType());
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.write(postBody);
out.close();
}
break;
case Method.GET:
connection.setRequestMethod("GET");
break;
case Method.DELETE:
connection.setRequestMethod("DELETE");
break;
case Method.POST:
connection.setRequestMethod("POST");
addBodyIfExists(connection, request);
break;
case Method.PUT:
connection.setRequestMethod("PUT");
addBodyIfExists(connection, request);
break;
default:
throw new IllegalStateException("Unknown method type.");
}
}

private static void addBodyIfExists(HttpURLConnection connection, Request<?> request) throws IOException, AuthFailureError {
//设置要发送的数据
byte[] body = request.getBody();
if (body != null) {
connection.setDoOutput(true);
connection.addRequestProperty(HEADER_CONTENT_TYPE, request.getBodyContentType());
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.write(body);
out.close();
}
}

private static HttpEntity entityFromConnection(HttpURLConnection connection) {
//得到数据
BasicHttpEntity entity = new BasicHttpEntity();
InputStream inputStream;
try {
inputStream = connection.getInputStream();
} catch (IOException ioe) {
inputStream = connection.getErrorStream();
}
entity.setContent(inputStream);
entity.setContentLength(connection.getContentLength());
entity.setContentEncoding(connection.getContentEncoding());
entity.setContentType(connection.getContentType());
return entity;
}
}

整个网络访问请求也就是正常的 HttpUrlConnection 的操作。

HttpClientStack.performRequest
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
public class HttpClientStack implements HttpStack {
@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError {
//得到封装好了的HttpUriRequest
HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);
//添加header
addHeaders(httpRequest, additionalHeaders);
addHeaders(httpRequest, request.getHeaders());
onPrepareRequest(httpRequest);
//走HttpClient的流程
HttpParams httpParams = httpRequest.getParams();
int timeoutMs = request.getTimeoutMs();
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
return mClient.execute(httpRequest);
}

static HttpUriRequest createHttpRequest(Request<?> request, Map<String, String> additionalHeaders) throws AuthFailureError {
switch (request.getMethod()) {
case Method.DEPRECATED_GET_OR_POST: {
byte[] postBody = request.getPostBody();
if (postBody != null) {
//如果是Post则返回HttpPost
HttpPost postRequest = new HttpPost(request.getUrl());
postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType());
HttpEntity entity;
entity = new ByteArrayEntity(postBody);
postRequest.setEntity(entity);
return postRequest;
} else {//Get方式的话返回HttpGet
return new HttpGet(request.getUrl());
}
}
case Method.GET:
return new HttpGet(request.getUrl());
case Method.DELETE:
return new HttpDelete(request.getUrl());
case Method.POST: {
HttpPost postRequest = new HttpPost(request.getUrl());
postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
setEntityIfNonEmptyBody(postRequest, request);
return postRequest;
}
case Method.PUT: {
HttpPut putRequest = new HttpPut(request.getUrl());
putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
setEntityIfNonEmptyBody(putRequest, request);
return putRequest;
}
default:
throw new IllegalStateException("Unknown request method.");
}
}
}

整个网络访问请求也就是正常的 HttpClient 的操作。

Request.parseNetworkResponse

这里我们用 StringRequest 举栗:

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
public class StringRequest extends Request<String> {
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException e) {
parsed = new String(response.data);
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
}

public class Response<T> {

/** Returns a successful response containing the parsed result. */
public static <T> Response<T> success(T result, Cache.Entry cacheEntry) {
return new Response<T>(result, cacheEntry);
}

/** Parsed response, or null in the case of error. */
public final T result;

/** Cache metadata for this response, or null in the case of error. */
public final Cache.Entry cacheEntry;

private Response(T result, Cache.Entry cacheEntry) {
this.result = result;
this.cacheEntry = cacheEntry;
this.error = null;
}

//blablabla......
}

再举个 JsonObjectRequest 的栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class JsonObjectRequest extends JsonRequest<JSONObject> {

@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString =
new String(response.data, HttpHeaderParser.parseCharset(response.headers));
return Response.success(new JSONObject(jsonString),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
}
ResponseDelivery.postResponse
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
public class ExecutorDelivery implements ResponseDelivery {
public ExecutorDelivery(final Handler handler) {
// Make an Executor that just wraps the handler.
mResponsePoster = new Executor() {
@Override
public void execute(Runnable command) {
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));
}

private 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()) {
mRequest.deliverResponse(mResponse.result);
} else {
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();
}
}
}
}

ResponseDeliveryRunnablemRequest.deliverResponse(mResponse.result) 中将结果传递出去,来看一下StringRequestdeliverResponse() :

1
2
3
4
5
6
7
8
9
10
11
12
public class StringRequest extends Request<String> {
public StringRequest(int method, String url, Listener<String> listener,
ErrorListener errorListener)
{

super(method, url, errorListener);
mListener = listener;
}

@Override
protected void deliverResponse(String response) {
mListener.onResponse(response);
}
}

这里,也就是返回给我们数据:

1
2
3
4
5
6
7
8
9
10
StringRequest stringRequest = new StringRequest("http://yydcdut.com",
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});

转一圈就这么转回来了。

查看 ResponseDelivery 流程图

说完 NetworkDispatcher 就该说一下 CacheDispatcher :

CacheDispatcher

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
public class CacheDispatcher extends Thread {
@Override
public void run() {
if (DEBUG) VolleyLog.v("start new dispatcher");
//设置线程优先级为后台
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

//cache的初始化,比如DiskBasedCache的话初始化中判断文件夹是否存在,不存在的话创建文件夹
mCache.initialize();

while (true) {
try {
//从队列中获取Request,没获取到的话一直阻塞在这个地方
final Request request = mCacheQueue.take();
request.addMarker("cache-queue-take");//log

// If the request has been canceled, don't bother dispatching it.
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
continue;
}

//从缓存中找到这个
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {
request.addMarker("cache-miss");
//cache中没有的话,加到network dispatcher中
mNetworkQueue.put(request);
continue;
}

//如果过期了,加到network dispatcher中
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
mNetworkQueue.put(request);
continue;
}

//如果有缓存,解析后通过mDelivery传递出去
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 {
// 需要refresh,先将response传递出去,再通过network dispatcher去refresh
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);

// Mark the response as intermediate.
response.intermediate = true;

mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
}
}
});
}

} catch (InterruptedException e) {
if (mQuit) {
return;
}
continue;
}
}
}
}

启动后会不断从缓存请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery 去执行后续处理。当结果未缓存过、缓存失效或缓存需要刷新的情况下,该请求都需要重新进入NetworkDispatcher 去调度处理。

查看 CacheDispatcher 流程图

StringRequest

介绍完了 Volley.newRequestQueue(context); 这部分,那么讲解一些准备 Request ,这部分拿 StringRequest 开导举栗子:

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
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);
mListener = listener;
}

public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
this(Method.GET, url, listener, errorListener);
}

@Override
protected void deliverResponse(String response) {
//回调出去
mListener.onResponse(response);
}

@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException e) {
parsed = new String(response.data);
}
//回调出去
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
}

其实 StringRequest 一看就明白了。

RequestQueue

准备好 Request 之后,就将 Request 通过 queue.add(stringRequest); 添加到 RequesrQueue 中。

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 RequestQueue {
//用来为Request生成计数
private AtomicInteger mSequenceGenerator = new AtomicInteger();
//存储当前添加进来的Request,包括正在执行的
private final Set<Request> mCurrentRequests = new HashSet<Request>();

private final Map<String, Queue<Request>> mWaitingRequests = new HashMap<String, Queue<Request>>();

public Request add(Request request) {
//将RequestQueue设置给Request
request.setRequestQueue(this);
//添加到mCurrentRequests中
synchronized (mCurrentRequests) {
mCurrentRequests.add(request);
}

//设置计数
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");//log

//如果不能缓存,直接加到network队列后返回,NetworkDispatcher的队列中有数据了就开始进行网络访问
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}

//在mWaitingRequests中找找
synchronized (mWaitingRequests) {
//这个cacheKey就是传入request的URL
String cacheKey = request.getCacheKey();
if (mWaitingRequests.containsKey(cacheKey)) {
//如果之前就缓存过
Queue<Request> stagedRequests = mWaitingRequests.get(cacheKey);
if (stagedRequests == null) {
stagedRequests = new LinkedList<Request>();
}
stagedRequests.add(request);
mWaitingRequests.put(cacheKey, stagedRequests);
if (VolleyLog.DEBUG) {
VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
}
} else {
//如果之前没有缓存过,添加到mWaitingRequests和mCacheQueue
mWaitingRequests.put(cacheKey, null);
//CacheDispatcher的队列中有数据了,进行缓存判断,有缓存直接返回,没缓存再访问网络
mCacheQueue.add(request);
}
return request;
}
}
}

首先会会判断当前的 Request 是否可以缓存,如果不能缓存则在直接加入网络请求队列,可以缓存的话则在加入缓存队列。在默认情况下,每个 Request 都是可以缓存的,当然我们也可以调用 Request.setShouldCache(false) 设置成不可缓存。这里会发现,如果 mWaitingRequests 中有 cacheKey 这个 Key 的话,似乎没有加到 NetworkQueue 或者 CacheQueue 中,是怎么回事呢?

答案:如果一个 Request 完成之后,会调用 Request.finish() ,而正好 Request 的成员变量中有 RequestQueue

1
2
3
4
5
6
7
8
public abstract class Request<T> implements Comparable<Request<T>> {
void finish(final String tag) {
if (mRequestQueue != null) {
mRequestQueue.finish(this);
}
//blablabla......
}
}

再看看 RequestQueue.finish() :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class RequestQueue {
void finish(Request request) {
//从mCurrentRequests中remove掉
synchronized (mCurrentRequests) {
mCurrentRequests.remove(request);
}

if (request.shouldCache()) {
synchronized (mWaitingRequests) {
//如果能缓存的话,从mWaitingRequests中remove掉
String cacheKey = request.getCacheKey();
Queue<Request> waitingRequests = mWaitingRequests.remove(cacheKey);
if (waitingRequests != null) {
if (VolleyLog.DEBUG) {
VolleyLog.v("Releasing %d waiting requests for cacheKey=%s.", waitingRequests.size(), cacheKey);
}
//再将同样cacheKey的加入到缓存队列中
mCacheQueue.addAll(waitingRequests);
}
}
}
}
}

这里就解决了上面那个问题,是因为目前已经有相同 cacheKey 的 Request 在 dispatcher 了,所以加到了等待列表中。

查看 RequestQueue.add(request) 流程图

至此,Volley 的解析就结束了。

总结

总体框架流程图

总体框架流程图

Volley.newRequestQueue(context)

Volley.newRequestQueue(context)

NetworkDispatcher流程图

NetworkDispatcher

CacheDispatcher流程图

CacheDispatcher

ResponseDelivery流程图

ResponseDelivery

RequestQueue.add(request)

RequestQueue.add(Request)

参考