学习完了CacheDispatcher这个类,下面我们看下NetworkDispatcher这个类的具体细节,先上代码:

/**
* 提供一个线程执行网络调度的请求分发
* Provides a thread for performing network dispatch from a queue of requests.
*
* 请求被添加到了指定的队列中
* 返回的数据通过ResponseDelivery接口返回
* Requests added to the specified queue are processed from the network via a
* specified {@link Network} interface. Responses are committed to cache, if
* eligible, using a specified {@link Cache} interface. Valid responses and
* errors are posted back to the caller via a {@link ResponseDelivery}.
*/
public class NetworkDispatcher extends Thread {
/** The queue of requests to service. */
private final BlockingQueue<Request<?>> mQueue;
/** The network interface for processing requests. */
private final Network mNetwork;
/** The cache to write to. */
private final Cache mCache;
/** For posting responses and errors. */
private final ResponseDelivery mDelivery;
/** Used for telling us to die. */
private volatile boolean mQuit = false; /**
* 创建一个新的网络调度线程,必须调用start()方法开启处理线程
* Creates a new network dispatcher thread. You must call {@link #start()}
* in order to begin processing.
*
* @param queue Queue of incoming requests for triage
* @param network Network interface to use for performing requests 执行请求
* @param cache Cache interface to use for writing responses to cache
* @param delivery Delivery interface to use for posting responses 结果返回
*/
public NetworkDispatcher(BlockingQueue<Request<?>> queue,
Network network, Cache cache,
ResponseDelivery delivery) {
mQueue = queue;
mNetwork = network;
mCache = cache;
mDelivery = delivery;
} /**
* 防止超时还一直占用资源
* 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();
} @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private void addTrafficStatsTag(Request<?> request) {
// Tag the request (if API >= 14)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
}
} @Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
while (true) {
long startTimeMs = SystemClock.elapsedRealtime();
Request<?> request;
try {
// Take a request from the queue.
// 获取一个请求消息
request = mQueue.take();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
} try {
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;
} addTrafficStatsTag(request); // 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.
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
continue;
} // Parse the response here on the worker thread.
// 对返回的响应进行处理
Response<?> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete"); // Write to cache if applicable.
// 将返回的响应消息写入Cache缓存
// 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) {
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
parseAndDeliverNetworkError(request, volleyError);
} catch (Exception e) {
VolleyLog.e(e, "Unhandled exception %s", e.toString());
VolleyError volleyError = new VolleyError(e);
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
mDelivery.postError(request, volleyError);
}
}
} private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {
error = request.parseNetworkError(error);
mDelivery.postError(request, error);
}
}

网络调度线程也是从队列中取出请求并且判断是否被取消了,如果没取消就去请求网络得到响应并回调给主线程。请求网络时调用this.mNetwork.performRequest(request),这个mNetwork是一个接口,实现它的类是BasicNetwork,我们下一个就需要看看BasicNetwork的performRequest()方法。

下面这张图是网络调度线程的执行控制流图:

现在跟着代码流程走到了BasicNetwork这个类中,这个类通过HttpStack这个接口去处理请求队列中的请求消息。这个类中只有一个核心方法performRequest(),这个方法的目的就是构造一个返回响应消息。

/**
* 这个方法主要就是构造new NetWorkResponse()的构造函数,
* 1.HTTP状态码
* 2.响应消息体
* 3.响应返回的消息头
* 4.返回304或者缓存命中则为TRUE
* 5.返回响应的时间
* @param request Request to process
* @return
* @throws VolleyError
*/
@Override
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while (true) {
HttpResponse httpResponse = null;
byte[] responseContents = null;
Map<String, String> responseHeaders = Collections.emptyMap();
try {
// Gather headers.
// 收集请求消息头信息
Map<String, String> headers = new HashMap<String, String>();
addCacheHeaders(headers, request.getCacheEntry()); //调用HttpStack进行网络访问,获取返回响应值
httpResponse = mHttpStack.performRequest(request, headers);
//获取返回响应状态以及响应返回码
StatusLine statusLine = httpResponse.getStatusLine();
int statusCode = statusLine.getStatusCode();
//返回消息头信息
responseHeaders = convertHeaders(httpResponse.getAllHeaders());
//SC_NOT_MODIFIED就是304请求响应
//对304响应请求的处理流程
if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
Entry entry = request.getCacheEntry();
if (entry == null) {
//如果是304请求,且没有改动,则返回304状态码,响应消息头,以及从请求到响应的时间
return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null,
responseHeaders, true,
SystemClock.elapsedRealtime() - requestStart);
} // A HTTP 304 response does not have all header fields. We
// have to use the header fields from the cache entry plus
// the new ones from the response.
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
// 304的返回消息头信息如果不为空,我们需要从缓存消息中获取完整的消息去填充完整响应消息头
// 最后返回完整的响应消息头
entry.responseHeaders.putAll(responseHeaders);
return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,
entry.responseHeaders, true,
SystemClock.elapsedRealtime() - requestStart);
} // Some responses such as 204s do not have content. We must check.
// 对204返回码的验证
if (httpResponse.getEntity() != null) {
responseContents = entityToBytes(httpResponse.getEntity()); //将HTTP中返回的内容转换成字节数组
} else {
// Add 0 byte response as a way of honestly representing a
// no-content request.
responseContents = new byte[0];
} // if the request is slow, log it.
// 如果请求时间过长则产生日志进行记录
long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
logSlowRequests(requestLifetime, request, responseContents, statusLine); // 其他请求返回码的处理,抛出IO异常
if (statusCode < 200 || statusCode > 299) {
throw new IOException();
}
//返回响应消息头
return new NetworkResponse(statusCode, responseContents, responseHeaders, false,
SystemClock.elapsedRealtime() - requestStart);
} catch (SocketTimeoutException e) {
attemptRetryOnException("socket", request, new TimeoutError());
} catch (ConnectTimeoutException e) {
attemptRetryOnException("connection", request, new TimeoutError());
} catch (MalformedURLException e) {
throw new RuntimeException("Bad URL " + request.getUrl(), e);
} catch (IOException e) {
int statusCode;
if (httpResponse != null) {
statusCode = httpResponse.getStatusLine().getStatusCode();
} else {
throw new NoConnectionError(e);
}
VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
//对网络返回的数据进行验证,对错误的响应进行处理
NetworkResponse networkResponse;
if (responseContents != null) {
networkResponse = new NetworkResponse(statusCode, responseContents,
responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
if (statusCode == HttpStatus.SC_UNAUTHORIZED || //401以及403响应消息
statusCode == HttpStatus.SC_FORBIDDEN) {
attemptRetryOnException("auth",
request, new AuthFailureError(networkResponse));
} else if (statusCode >= 400 && statusCode <= 499) {
// Don't retry other client errors.
//编号为400—499范围的状态码表用户的请求未完成并需要用户提供更多的信息来实现对所需资源的访问
throw new ClientError(networkResponse);
} else if (statusCode >= 500 && statusCode <= 599) {
//由于内部服务器错误造成的
if (request.shouldRetryServerErrors()) {
attemptRetryOnException("server",
request, new ServerError(networkResponse));
} else {
throw new ServerError(networkResponse);
}
} else {
// 3xx? No reason to retry.
throw new ServerError(networkResponse);
}
} else {
attemptRetryOnException("network", request, new NetworkError());
}
}
}
}

下面是这个方法的流程图:

下面再来看下他的成员变量

//最长请求时间
private static final int SLOW_REQUEST_THRESHOLD_MS = 3000; //线程池的内存容量大小
private static final int DEFAULT_POOL_SIZE = 4096; //真正执行网络请求的类
protected final HttpStack mHttpStack; protected final ByteArrayPool mPool;
  • 两个常量,分别表示最长请求时间和线程池大小
  • 一个HttpStack 接口,真正执行网络请求的类
  • 二进制数组池,一个工具类

从构造函数中可以看出网络请求最终是由HTTPStack完成的。

扫码顺序:

参考相关网站:

http://www.jianshu.com/p/e475f4479fb2

http://www.jianshu.com/p/33be82da8f25  手撕1

http://www.jianshu.com/p/358b766c8d27  手撕2

http://www.jianshu.com/p/63c0cd0fd99c  手撕3

201709021工作日记--Volley源码详解(五)的更多相关文章

  1. 201709011工作日记--Volley源码详解(二)

    1.Cache接口和DiskBasedCache实现类 首先,DiskBasedCache类是Cache接口的实现类,因此我们需要先把Cache接口中的方法搞明白. 首先分析下Cache接口中的东西, ...

  2. 20170908工作日记--Volley源码详解

    Volley没有jar包,需要从官网上下载源码自己编译出来,或者做成相关moudle引入项目中.我们先从最简单的使用方法入手进行分析: //创建一个网络请求队列 RequestQueue reques ...

  3. 201709011工作日记--Volley源码详解(三)

    1. RequestQueue类 我们使用 Volley 的时候创建一个 request 然后把它丢到 RequestQueue 中就可以了.那么来看 RequestQueue 的构造方法,含有四个参 ...

  4. 201709021工作日记--Volley源码解读(四)

    接着volley源码(三)继续,本来是准备写在(三)后面的,但是博客园太垃圾了,写了半天居然没保存上,要不是公司这个博客还没被限制登陆,鬼才用这个...真是垃圾 继续解读RequestQueue的源码 ...

  5. OkHttp3源码详解(五) okhttp连接池复用机制

    1.概述 提高网络性能优化,很重要的一点就是降低延迟和提升响应速度. 通常我们在浏览器中发起请求的时候header部分往往是这样的 keep-alive 就是浏览器和服务端之间保持长连接,这个连接是可 ...

  6. 20170906工作日记--volley源码的相关方法细节学习

    1. 在StringRequest类中的75行--new String();使用方法 /** * 工作线程将会调用这个方法 * @param response Response from the ne ...

  7. Activiti架构分析及源码详解

    目录 Activiti架构分析及源码详解 引言 一.Activiti设计解析-架构&领域模型 1.1 架构 1.2 领域模型 二.Activiti设计解析-PVM执行树 2.1 核心理念 2. ...

  8. 源码详解系列(六) ------ 全面讲解druid的使用和源码

    简介 druid是用于创建和管理连接,利用"池"的方式复用连接减少资源开销,和其他数据源一样,也具有连接数控制.连接可靠性测试.连接泄露控制.缓存语句等功能,另外,druid还扩展 ...

  9. [转]【视觉 SLAM-2】 视觉SLAM- ORB 源码详解 2

    转载地址:https://blog.csdn.net/kyjl888/article/details/72942209 1 ORB-SLAM2源码详解 by 吴博 2 https://github.c ...

随机推荐

  1. springMVC学习记录3-拦截器和文件上传

    拦截器和文件上传算是springmvc中比较高级一点的内容了吧,让我们一起看一下. 下面先说说拦截器.拦截器和过滤器有点像,都可以在请求被处理之前和请求被处理之到做一些额外的操作. 1. 实现Hand ...

  2. 发布MVC项目到服务器上时候遇到的 模块 DirectoryListingModule 通知 ExecuteRequestHandler 处理程序 StaticFile 错误代码 0x00000000

    应用程序“HMW121197”中的服务器错误错误摘要HTTP 错误 403.14 - ForbiddenWeb 服务器被配置为不列出此目录的内容. 详细错误信息模块 DirectoryListingM ...

  3. C++中的浅拷贝和深拷贝

    浅拷贝(shallow copy)与深拷贝(deep copy)对于值拷贝的处理相同,都是创建新对象,但对于引用拷贝的处理不同,深拷贝将会重新创建新对象,返回新对象的引用字.浅拷贝不会创建新引用类型. ...

  4. ECMAScript6新特性之Array API

    一 填充数组 var arr = new Array(5); arr.fill('abc',2,4); console.log('Array.prototype.fill',arr); // [und ...

  5. 【Python基础教程第2版】——第二讲:列表和元组

    引言: 什么是数据结构? 数据结果是通过某种方式(例如对元素进行编号)组织在一起的数据元素的集合.Python中最常用的数据结构是序列. Python包含6种内建的序列:列表和元组(最常用:列表可以修 ...

  6. python 网络客户端编程端口,模块

    协议 功能 端口 模块 HTTP 网页 80 httplib,urllib,xmlrpclib NNTP Usenet 新闻组 119 nntplib FTP 文件传输 20(21控制和命令端口) f ...

  7. 14- Servlet.service() for servlet [mvc-dispatcher] in context with path [/collegeservice] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root caus

    有的service没有依赖注入:

  8. php 的多进程实践

    php的多进程处理依赖于pcntl扩展,通过pcntl_fork创建子进程来进行并行处理.   例1如下: <?php $pid = pcntl_fork(); if($pid == -1) { ...

  9. .net 4.0的Lazy<T>方法,反射实现延迟加载。

    //自己山寨.public class YaLazy<T> { private bool _isValueCreated = false; public bool IsValueCreat ...

  10. Oracle 基础表查询

    --查询所有用户表的数据 SELECT * FROM ALL_TABLES WHERE OWNER='USER_NAME' --如果是用该用户登录使用以下语句: SELECT * FROM USER_ ...