您的位置:首页 > 理论基础 > 计算机网络

Part3:Volley传递者原理分析

2016-07-23 01:27 323 查看
问题产生

创建传递者

传递的过程

一个比较重要的细节

问题产生

我们先看一下Volley的使用方法:

//第一步,创建一个RequestQueue队列
RequestQueue mQueue = Volley.newRequestQueue(context);
//第二步,创建一个具体类型的对象,这里是StringRequest
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);
}
});
//第三步,将stringRequest放入queue中
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) {
// 所有的Runnable通过绑定主线程Looper的Handler对象最终在主线程执行.
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() {
// 如果request被取消,则不回调用户设置的Listener接口
if (mRequest.isCanceled()) {
mRequest.finish("canceled-at-delivery");
return;
}

// 通过response状态标志,来判断是回调用户设置的Listener接口还是ErrorListener接口
if (mResponse.isSuccess()) {
mRequest.deliverResponse(mResponse.result);
} else {
mRequest.deliverError(mResponse.error);
}

if (mResponse.intermediate) {
mRequest.addMarker("intermediate-response");
} else {
// 通知RequestQueue终止该Request请求
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();
}
}
});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息