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

Volley框架的基本解读(二)

2016-05-23 14:51 645 查看
Volley框架的基本解读(一)中我们说了Volley与RequestQueue两个重要的类,说到了CacheDispatcher与NetworkDispatcher这两个调度类,比起缓存调度,我想大家可能会对网络调度更感兴趣,我们来看看:

public class NetworkDispatcher extends Thread


这个网络调度类本质是一个线程

public NetworkDispatcher(BlockingQueue<Request> queue,
Network network, Cache cache,
ResponseDelivery delivery) {
mQueue = queue;
mNetwork = network;
mCache = cache;
mDelivery = delivery;
}


里面只有一个构造方法,从RequestQueue中传入的四个参数,分别是优先级队列,网络处理类,缓存处理类,结果分发类,回想一下,在RequestQueue的start方法中,NetworkDispatcher被创建后,便调用了NetworkDispatcher的start方法,因为它是一个线程,我们来看看run方法:

@Override
public void run() {
// 设置最高线程优先级
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Request request;
while (true) {
try {
// Take a request from the queue.
request = mQueue.take();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
// interrupt方法会尝试中断本线程,我们可能会被打断,因为这是该放弃的时候了
if (mQuit) {
return;
}
continue;
}

try {
// 调试标记:以成功取出队列中的request
request.addMarker("network-queue-take");

// If the request was cancelled already, do not perform the
// network request.
if (request.isCanceled()) {
request.finish("network-discard-cancelled");
continue;
}

// Tag the request (if API >= 14)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// 流量统计标记,配合DDMS工具统计流量使用情况
TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
}

// Perform the network request.
// 前戏结束,这里就是真正的网络请求
NetworkResponse networkResponse = mNetwork.performRequest(request);
// 调试标记:网络请求完成(因线程异步,该标记只做调试之用)
request.addMarker("network-http-complete");

// If the server returned 304 AND we delivered a response already,
// we're done -- don't deliver a second identical response.
// 如果服务器返回无修改,并requset以完成分发,说明进行了重复的请求,移除该request
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
continue;
}

// Parse the response here on the worker thread.
// 交由Request进行解析Response
Response<?> response = request.parseNetworkResponse(networkResponse);
// 调试标记:网络请求解析完成
request.addMarker("network-parse-complete");

// Write to cache if applicable.
// TODO: Only update cache metadata instead of entire record for 304s.
// 写入缓存
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}

// Post the response back.
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));
}
}
}


看重点,mQueue是一个用于保存requset的网络优先级队列,我们在使用volley框架时,通过mQueue.add(stringRequest)该方法将request加入到RequestQueue中,而在RequestQueue中又将该request加入了PriorityBlockingQueue<Request>这样一个以优先级排序的队列中,也就是这里的mQueue。

上面源码我们可以看到,run方法中是一个while死循环,不断的试图从mQueue队列中取出request,try.....catch中的意义等会再说,然后就是各种判断,如果request标记取消,就结束这次网络请求,如果api大于14,进行流量统计,后面这句代码是重点:

// 前戏结束,这里就是真正的网络请求
NetworkResponse networkResponse = mNetwork.performRequest(request);


现在我们知道,NetworkDispatcher为什么是网络调度线程?因为它只负责将request传给mNetwork网络处理类,本身并不执行网络请求。

接着看,如果请求结果无修改并requset以完成分发,说明进行了重复的请求,结果无需返回。NetworkResponse是一个对返回结果封装的实体类,request对其进行解析,parseNetworkResponse该方法是一个抽象方法,request可以有很多具体实现子类,因此解析的方式只能由子类具体实现,如果需要缓存,将返回的数据加入缓存处理类中,最后由结果分发类调用postResponse(request, response)发起回调。

这里的内容有点多,可能有点乱,但多数是简单的判断,大家明白意义即可,具体的下面分析,在此之前我们再看两个方法:

/**
* 通知错误
*/
private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {
error = request.parseNetworkError(error);
mDelivery.postError(request, error);
}


在上面的run方法中当catch捕捉到VolleyError异常,便会交给该方法处理,大概意思就是让request.parseNetworkError(error)解析这个错误,然后发起错误回调,值得一提的是parseNetworkError在request中是一个没有意义的方法,传进去的VolleyError会被原封不动的返回,但子类可以复写该方法,完成自己的错误解析。

/**
* Forces this dispatcher to quit immediately.  If any requests are still in
* the queue, they are not guaranteed to be processed.
*
* 标记取消网络请求,并中断该线程
*/
public void quit() {
mQuit = true;
interrupt();
}


这个方法大家看的是不是有点眼熟,它正是RequestQueue的stop方法中出现的,用于中断线程,代码很简单,改变了标记并调用了interrupt这个Thread中定义的尝试中断线程的方法,如果这个方法被调起,线程被中断会出现什么情况?大家想起了上面run方法中的try......catch了没,在catch中有这么一段代码:

// interrupt方法会尝试中断本线程,我们可能会被打断,因为这是该放弃的时候了
if (mQuit) {
return;
}
continue;


interrupt方法会尝试中断本线程,while死循环即会抛出异常,mQuit为true,while循环被跳出,逻辑相当的精巧,有木有!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息