在Volley源码解析 (一)中简单的说明了volley的执行流程:从Request到生成NetWorkResponse的过程,本文就上篇博客的基础上继续讲解最后一步——>生成Response的过程(本篇的读者建议先大致看下《Volley 源码解析(一)》。
简单了解下Network Response:
NetworkResponse包含了网络返回的主要数据:比如原始数据的字节数组,服务器header信息等,代码如下:
/** http状态码. */
public final int statusCode;
/** 服务器响应的原始数据 */
public final byte[] data;
/** 响应http首部*/
public final Map headers;
也就是说我们通过操作BasicNetwork返回的NetworkResponse来对原始数据进行处理;换句话说我们可以不通过volley提供的Response
,Response
,Response
等对象,而我们自己对原始数据进行转换和使用。
比如下面代码,发起一个请求,然后将数据转换成字符串:
//创建一个请求对象
StringRequest request = new StringRequest("http://www.baidu.com",null,null);
//利用HurlStack创建一个BasicNetwork对象
BasicNetwork basicNetwork = new BasicNetwork(new HurlStack());
//发起请求,返回NetWorkResponse
NetworkResponse networkResponse = basicNetwork.performRequest(request);
//将原始数据转换成字符串
String str = new String(networkResponse.data);
//对Str进行打印。输出结果如下:
通过上面几行代码我们就可以获取想要的字符串了,那么volley对是怎么获取String的呢?在StringRequest的基类Request提供了一个抽象方法:
//注意该方法返回的是Response对象
abstract protected Response parseNetworkResponse(NetworkResponse response);
所以我们可以看看StringRequest类对此抽象方法的具体实现:
protected Response 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));
}
代码很简单,也就是讲NetworkRespone的data和header转换成parsed 字符串,然后交给Response的success方法,最终返回一个Response
对象的过程:
public static Response success(T result, Cache.Entry cacheEntry) {
//将处理的结果交给result来持有
return new Response(result, cacheEntry);
}
所以如果读者想简单了解ImageRequest的Bitmap是怎么生成的,就可以参看ImageRequest的parseNetworkResponse方法,同样的道理可以了解volley的JsonReqeust对象JsonObject构建原理,此处不在赘述。
我们可以通过Response的result来获取我们需要的数据对象Bitmap,JsonObject,String等。
简单对上文的说明做下总结,也是volley工作流程大致过程: 1、构建相应的Request对象 2、Volley使用BasicNetwork对象的performRequest(request)发起数据请求,获得NetworkResponse对象 3、将NetworkResponse交给Request的parseNetworkResponse方法,将networkResponse持有的原始数据data(byte[])转换成具体的对象:比如String、Bitmap、JsonObject等。 4、将步骤3生成对象数据交给Response对象的result对象持有,从而交给客户端使用。
不知道读者发现没有,到此为止,扯了这么多,博主使用没有说明上述的这些过程在Volley时怎么发起的!!!比如BasicNetwork的performRequest是什么时候调用的?parseNetworkResponse又是什么时候调用的,Response对象又是怎么交给客户端的呢?下面就来讲解下这部分。
通常一些耗时的操作都需要在线程中去处理,网络请求也不例外,Volley亦然!!Volley提供了一个NetworkDispatcher的线程类(Thread的子类),这个线程类的主要作用就是执行上面讲解的四个步骤!所以看看其run方法都做了些什么:
public void run() {
while (true) {//一个while循环
Request request;
try {
//从队列里获取一个请求
request = mQueue.take();
} catch (InterruptedException e) {
if (mQuit) {
return;
}
continue;
}
try {
//如果客户端取消了请求,则调用请求回调接口通知客户端
if (request.isCanceled()) {
request.notifyListenerResponseNotUsable();
//继续循环获取队列里的下一个请求
continue;
}
//执行BasicNetwork的performReqeust方法
NetworkResponse networkResponse = mNetwork.performRequest(request);
//如果服务服返回304状态吗,并且我们已经将请求交付给客户端
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
//告诉服务端没有有效的响应数据
request.notifyListenerResponseNotUsable();
//继续循环,获取队列中的下一个请求
continue;
}
//在工作线程将数据转换成Response对象
Response response = request.parseNetworkResponse(networkResponse);
//开始缓存
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry);
}
//标记当前响应已经交给客户端
request.markDelivered();
//发送响应数据给客户端
//主要是回调Listener接口,通知客户端获取数据
mDelivery.postResponse(request, response);
request.notifyListenerResponseReceived(response);
} catch (VolleyError volleyError) {
} catch (Exception e) {
}
}
}
上面的代码执行流程也清晰,简单来说就是不断从请求队列中获取一个请求,拿到一个Request对象之后其核心逻辑也就是调用BasicNetwork对象的performRequest获取NetworkResponse对象;然后调用Request的parseNetworkResponse方法来构架自己所需要的响应对象。
RequestQueue简单描述:
注意上面说到了请求队列的东西,在volley中用RequestQueue来表示volley的请求队列,该类有如下属性:
//记录当前请求对象
private final Set>();
/** 缓存相关(本篇博文暂且不谈) */
private final PriorityBlockingQueue> mNetworkQueue =
new PriorityBlockingQueue();
可以看出RequestQueue一个优先级阻塞队列mNetworkQueue来添加请求。本文暂且不谈缓存功能。先来分析分析volley怎么向该队列添加请求对象,在RequestQueue中有add方法:
public Request add(Request request) {
//设置request所属的队列
request.setRequestQueue(this);
//此处省略部分代码
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
//此处省略部分代码
return request;
}
抛开缓存等功能(省略的代码)不说,add方法也就是向队列中不断添加Request对象,然后各个请求对象与请求队列进行绑定,简单的关系如图所示: 然后这些队列中的请求对象又被NetworkDispatcher不断获取发起网络请求。在RequestQueue中提供了start方法来开启NetworkDispatcher线程:
public void start() {
// 默认 mDispatchers.length=4,开启四个
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
在volley中一共开启了四个NetworkDispatcher线程对象来从同一个队列中获取请求对象,然后不断发起http请求,结合以上说明,volley的请求过程可以入下图表示:
那么客户端是怎么拿到这些数据的呢?就且听下回分解吧。