Volley
Demo
1 | RequestQueue mQueue = Volley.newRequestQueue(this); |
时序图
分析
Volley.newRequestQueue()方法
有几个重载函数,最终是调用的这里,可以看到首先根据 sdk 版本是否大于等于9,去生成不同的 Network 对象.
(可以看到在 sdk9 之前,不建议使用 HttpUrlConnection)
然后初始化缓存目录,实例化 RequestQueue 对象,最后调用 start() 方法并 return queue.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
32public static RequestQueue newRequestQueue(Context context, BaseHttpStack stack) {
BasicNetwork network;
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
network = new BasicNetwork(new HurlStack());
} else {
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
// At some point in the future we'll move our minSdkVersion past Froyo and can
// delete this fallback (along with all Apache HTTP code).
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException e) {
}
network = new BasicNetwork(
new HttpClientStack(AndroidHttpClient.newInstance(userAgent)));
}
} else {
network = new BasicNetwork(stack);
}
return newRequestQueue(context, network);
}
private static RequestQueue newRequestQueue(Context context, Network network) {
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();
return queue;
}Network/BasicNetwork/HurlStack/HttpClientStack 分别是啥?
BasicNetwork 是 Network 的实现类,只有一个 performRequest 祖传方法,具体是根据 request 执行网络请求返回 NetworkResponse.
1
2
3
4
5
6public interface Network {
/**
* Performs the specified request.
*/
NetworkResponse performRequest(Request<?> request) throws VolleyError;
}HurlStack 和 HttpClientStack 是 HttpStack 的两个子类,分别是 HttpUrlConnection 的实现和 HttpClient的实现,
也就是真正执行网络请求的地方,可以看出 Network 内部执行网络请求是调用了它.1
2
3
4
5
6
7
8
9public interface HttpStack {
/**
* Performs an HTTP request with the given parameters.
* @return the HTTP response
*/
HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError;
}DiskBasedCache 是什么
看名字可以猜出是缓存相关的,它是 Cache 的具体实现类,主要是管理缓存的,包括读取缓存,写入缓存,清除缓存等.
1
2
3
4
5
6
7
8
9
10
11public interface Cache {
Entry get(String key);
void put(String key, Entry entry);
void initialize();
void invalidate(String key, boolean fullExpire);
void remove(String key);
void clear();
class Entry {
//...
}
}RequestQueue 作用是什么
分析到这里,就可以知道它是很重要的类了,它的构造函数需要传入 Cache 缓存管理对象, Network
网络请求类, threadPoolSize 线程池大小, 和 ResponseDelivery 对象,
ResponseDelivery 是第一次出现,它的作用就是将请求结果,response/error 返回给调用者.1
2
3
4
5
6
7public RequestQueue(Cache cache, Network network, int threadPoolSize,
ResponseDelivery delivery) {
mCache = cache;
mNetwork = network;
mDispatchers = new NetworkDispatcher[threadPoolSize];
mDelivery = delivery;
}1
2
3
4
5public interface ResponseDelivery {
void postResponse(Request<?> request, Response<?> response);
void postResponse(Request<?> request, Response<?> response, Runnable runnable);
void postError(Request<?> request, VolleyError error);
}RequestQueue.start() 方法做了什么
start() 首先会调用 stop(), 然后实例化 CacheDispatcher 对象和 mDispatchers 数组,
并分别启动线程,默认 mDispatchers 长度是4,也就是启动一个缓存线程,4个工作线程.
注意 mCacheQueue 和 mNetworkQueue 都是优先阻塞队列,且4个工作线程公用 mNetworkQueue1
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
30private final NetworkDispatcher[] mDispatchers;
private CacheDispatcher mCacheDispatcher;
private final PriorityBlockingQueue<Request<?>> mCacheQueue =
new PriorityBlockingQueue<>();
private final PriorityBlockingQueue<Request<?>> mNetworkQueue =
new PriorityBlockingQueue<>();
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();
}
}
}RequestQueue.add() 方法做了些什么
首先将 request 添加到 mCurrentRequests 集合,通过 setSequence()方法设置一个序列号,
最后根据 shouldCache() 方法判断 request 是否需要缓存,如果需要将它添加到 mCacheQueue 中,否则添加到 mNetworkQueue 中.
然后就完了,返回 request 对象.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();
public <T> Request<T> add(Request<T> request) {
// Tag the request as belonging to this queue and add it to the set of current requests.
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 the request is uncacheable, skip the cache queue and go straight to the network.
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
mCacheQueue.add(request);
return request;
}添加 request 后,NetworkDispatcher 和 CacheDispatcher 是怎么处理的?
在上一步中,request 根据缓存添加到 mCacheQueue 或 mNetworkQueue 阻塞队列中,这两个阻塞队列是被关联在 CacheDispatcher 和 NetworkDispatcher 中了。
可以想到这两分发器肯定是阻塞取出请求做处理。CacheDispatcher
主要看它的 run() 方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public void run() {
// 省略部分代码
while (true) {
final Request<?> request = mCacheQueue.take();
// 省略部分代码
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
continue;
}
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {
request.addMarker("cache-miss");
// Cache miss; send off to the network dispatcher.
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
mNetworkQueue.put(request);
}
continue;
}
.....
mDelivery.postResponse(request, response);
}
}和我猜想的一样,死循环,从阻塞队列中取出 request ,然后再做处理,判断是否去掉,判断是否过期,判断缓存中是否存在,如果不存在则加入到 mNetworkQueue ,
代表需要联网获取,否则,直接回调 mDelivery.postResponse 也就是结束的回调。总结一下,CacheDispatcher 主要是判断缓存是否可用,如果可用直接返回,不用网络请求了,否则,
会将 request 丢给 mNetworkQueue, 最终是由 NetworkDispatcher 处理的.NetworkDispatcher
它的 run 方法和上述 CacheDispatcher 类似,只不过是请求网络,再判断是否需要缓存,如果需要则保存,最后回调 mDelivery.
ExecutorDelivery 是怎么处理响应的
ExecutorDelivery 的默认实现是 NetworkDispatcher,在 RequestQueue 构造方法里可以看到,
传入了主线程的 Handler 对象,在 postResponse 和 postError 方法中,实际上调用了 handler.post()方法,
在主线程执行,而 ResponseDeliveryRunnable 的 run 方法里,
通过判断 mResponse.isSuccess() 请求是否成功,回调 request 的 deliverResponse()
和 deliverError()方法,最终回调了我们自定义的回调方法.总结一下,它的作用就是:将响应的结果 response 回调给 request 中的回调方法,并在主线程中进行.
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
44private final Executor mResponsePoster;
mResponsePoster = new Executor() {
public void execute(Runnable command) {
handler.post(command);
}
};
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
request.markDelivered();
request.addMarker("post-response");
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
}
public void postError(Request<?> request, VolleyError error) {
request.addMarker("post-error");
Response<?> response = Response.error(error);
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null));
}
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;
}
public void run() {
if (mRequest.isCanceled()) {
mRequest.finish("canceled-at-delivery");
return;
}
if (mResponse.isSuccess()) {
mRequest.deliverResponse(mResponse.result);
} else {
mRequest.deliverError(mResponse.error);
}
// ignore some code
}
}并发时怎么处理的?
由于采用了阻塞队列,所有的联网请求最终都是添加到 mNetworkQueue 这个队列中的,默认工作分发器 NetworkDispatcher 有4个,它们会从这个队列中取出请求,然后处理。
打个比方,当有一堆工作来的时候,4个人同时处理,且保证独立,也就是一个工作不会2个人同时做。HTTP 响应内容的解析在哪里?
在 request 的 parseNetworkResponse 里,比如 StringRequest 就是最简单的。这个方法在 NetworkDispatcher 处理请求完后调用,并最终传递给 ResponseDelivery ,再到回调.