问题产生
RequestQueue mQueue = Volley.newRequestQueue(context);
StringRequest stringRequest = new StringRequest("http://www.baidu.com",
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.d("TAG", response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("TAG", error.getMessage(), error);
}
});
queue.add(stringRequest)
- 前面的文章已经分析过了,当我们执行
RequestQueue mQueue = Volley.newRequestQueue(context);
,它的内部是创建了一个缓存线程和四个网络请求线程,它们会从优先级队列中去取request,如果没有则阻塞,当第三步把相应的请求加入到queue中后,队列中有数据了,线程就会正式执行.那不知道你有没有想过这个问题,请求拿到数据都是在异步线程中的,它到最后是如何跑到onResponse中的(请看上述代码第二步),而且还是这个函数还在主线程中?其实原理非常简单,我们就来稍微分析一下这个类:ExecutorDelivery
(网络请求结果传递类,将数据放到主线程中去处理)
创建传递者
- 先看一下入口,其实就是第一步时创建,注意Looper.getMainLooper(),它主动绑定了一个主线程中的Looper,这是它能把数据传递到主线程的原因
public RequestQueue(Cache cache, Network network) {
this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
}
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(cache, network, threadPoolSize,
new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}
- 紧接着看一下
ExecutorDelivery
的构造函数,看完构造函数后如何构造一个传递这就明白了,现在我们分析一下传递的过程
public ExecutorDelivery(final Handler handler) {
mResponsePoster = new Executor() {
@Override
public void execute(Runnable command) {
handler.post(command);
}
};
}
传递的过程
- 传递的入口都是在请求到数据之后,比如
CacheDispatcher
中得到数据后会调用mDelivery.postResponse(request, response);
方法,我们看一下这个方法,毫无疑问,最终执行的是ResponseDeliveryRunnable中的run方法
@Override
public void postResponse(Request<?> request, Response<?> response) {
postResponse(request, response, null);
}
@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
request.markDelivered();
mResponsePoster.execute(
new ResponseDeliveryRunnable(request, response, runnable)
);
}
- 我们再看一下
ResponseDeliveryRunnable
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;
}
@Override
public void run() {
if (mRequest.isCanceled()) {
mRequest.finish("canceled-at-delivery");
return;
}
if (mResponse.isSuccess()) {
mRequest.deliverResponse(mResponse.result);
} else {
mRequest.deliverError(mResponse.error);
}
if (mResponse.intermediate) {
mRequest.addMarker("intermediate-response");
} else {
mRequest.finish("done");
}
if (mRunnable != null) {
mRunnable.run();
}
}
}
- 先不要管别的逻辑,我们直接跟进
mRequest.deliverResponse(mResponse.result);
/** 将解析的String结果传递给用户的回调接口. */
@Override
protected void deliverResponse(String response) {
mListener.onResponse(response);
}
- 在顺便看一下
mRequest.deliverError(mResponse.error);
/** 将网络错误传递给回调接口. */
public void deliverError(VolleyError error) {
if (mErrorListener != null) {
mErrorListener.onErrorResponse(error);
}
}
- 把上面两段代码和第二步联系起来看,一切都会真相大白了
一个比较重要的细节
- 在ResponseDeliveryRunnable中的run方法里最后一段代码,这里会有人疑惑?为什么又跑到异步线程中去了?
if (mRunnable != null) {
mRunnable.start();
}
- 这个是因为在缓存过期时,会给用户先显示已过期的内容,但是立刻会去网络中请求数据,所以正常的传递逻辑不能少,但必须又包含在异步中请求数据的逻辑,请看入口(在CacheDispatcher中发现缓存失效 后)
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});