Volley源码解析
从newRequestQueue进行入手来进行一步步分析源码的流程
public static RequestQueue newRequestQueue(Context context) {
return newRequestQueue(context, null);
}
public static RequestQueue newRequestQueue(Context context, HttpStack stack)
{
return newRequestQueue(context, stack, -1);
}
我们可以查看出来,它进行重载了两个方法来进行使用,最后的方法是下面这个
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
//参数一:缓存到手机内置内存中
//参数二:通过查看我们可以发现,这个文件夹的名字是volley
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
String userAgent = "volley/0";
try {
//获取用户包名
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
//用户代理,通过包名+版本号来实现的
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException e) {
}
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
//HttpUrlConnection中的stack
stack = new HurlStack();
} else {
//HttpClient中的HttpClientStack
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
Network network = new BasicNetwork(stack);
RequestQueue queue;
if (maxDiskCacheBytes <= -1)
{
// No maximum size specified
queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
}
else
{
// Disk cache size specified
queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
}
queue.start();
return queue;
}
通过上面的代码我们可以看出来,它会判断当前的sdk的大小,如果当前的sdk>=9,它会调用HurlStack(),否则,它会调用HttpClientStack这个方法
1.HurlStack 与 HttpClientStack 区别
由此可见,在Android 2.2 中HttpClient拥有较少的bug,所以使用它比较合适,在Android 2.3以后HttpUrlConnection是最佳的选择。它的api简单,体积比较小,因此非常试用于Android项目。压缩和缓存机制可以有效的减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。对于新的应用程序应该更加偏向于使用HttpURLConnection,因为在以后的工作当中我们也会将更多的时间放在优化HttpURLConnection上面。
-
HurlStack中的父类的源码进行分析
/** * An HTTP stack abstraction. * 抽象的http栈 */ public interface HttpStack { /** * Performs an HTTP request with the given parameters. * 根据参数,执行http请求 * <p>A GET request is sent if request.getPostBody() == null. A POST request is sent otherwise, * and the Content-Type header is set to request.getPostBodyContentType().</p> * * @param request the request to perform * @param additionalHeaders additional headers to be sent together with * {@link Request#getHeaders()} * @return the HTTP response */ public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError; }
该父类主要规定了,子类必须有一个根据request请求数据,并且返回HttpResponse类的方法
OK,接下来我们先看HurlStack,这个类使用的是HttpURLConnection作为连接方式,在sdk较高版本推荐使用(其实目前市场上2.3的系统已经很少见了)
我们直接看这个类的核心方法performRequest()
@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
String url = request.getUrl();
HashMap<String, String> map = new HashMap<String, String>();
map.putAll(request.getHeaders());
map.putAll(additionalHeaders);
if (mUrlRewriter != null) {
String rewritten = mUrlRewriter.rewriteUrl(url);
if (rewritten == null) {
throw new IOException("URL blocked by rewriter: " + url);
}
url = rewritten;
}
URL parsedUrl = new URL(url);
HttpURLConnection connection = openConnection(parsedUrl, request);//开启连接
for (String headerName : map.keySet()) {//添加请求参数
connection.addRequestProperty(headerName, map.get(headerName));
}
setConnectionParametersForRequest(connection, request);//设置请求方式
// Initialize HttpResponse with data from the HttpURLConnection.
ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);//http协议
int responseCode = connection.getResponseCode();//获取响应状态
if (responseCode == -1) {//-1说明没有响应,抛出异常
// -1 is returned by getResponseCode() if the response code could not be retrieved.
// Signal to the caller that something was wrong with the connection.
throw new IOException("Could not retrieve response code from HttpUrlConnection.");
}
StatusLine responseStatus = new BasicStatusLine(protocolVersion,
connection.getResponseCode(), connection.getResponseMessage());//响应状态类
BasicHttpResponse response = new BasicHttpResponse(responseStatus);
response.setEntity(entityFromConnection(connection));//解析响应实体
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {//添加响应头
if (header.getKey() != null) {
Header h = new BasicHeader(header.getKey(), header.getValue().get(0));
response.addHeader(h);
}
}
return response;
}
整个方法分成几个步骤,首先是将请求参数,存储到map当中
HashMap<String, String> map = new HashMap<String, String>();
map.putAll(request.getHeaders());
map.putAll(additionalHeaders);
然后是开启url连接
URL parsedUrl = new URL(url);
HttpURLConnection connection = openConnection(parsedUrl, request);//开启连接
来看openConnection()方法
/**
* Opens an {@link HttpURLConnection} with parameters.
* 开启网络连接
* @param url
* @return an open connection
* @throws IOException
*/
private HttpURLConnection openConnection(URL url, Request<?> request) throws IOException {
HttpURLConnection connection = createConnection(url);
int timeoutMs = request.getTimeoutMs();
connection.setConnectTimeout(timeoutMs);
connection.setReadTimeout(timeoutMs);
connection.setUseCaches(false);
connection.setDoInput(true);
// use caller-provided custom SslSocketFactory, if any, for HTTPS
if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {//https
((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory);
}
return connection;
}
/**
* Create an {@link HttpURLConnection} for the specified {@code url}.
*/
protected HttpURLConnection createConnection(URL url) throws IOException {
return (HttpURLConnection) url.openConnection();
}
这个方法主要就是调用url.openConnevtion()从而返回一个HttpURLConnection对象,其中的一些超时设置,是由request本身提供的
另外还根据url是否带有https,为HttpURLConnection设置setSSLSocketFactory(mSslSocketFactory对象是在构造方法中传入的)
得到HttpURLConnection,就设置请求参数
for (String headerName : map.keySet()) {//添加请求参数
connection.addRequestProperty(headerName, map.get(headerName));
}
然后是确定请求方式(GET,POST还是别的)
setConnectionParametersForRequest(connection, request);//设置请求方式
setConnectionParametersForRequest方法:
@SuppressWarnings("deprecation")
/**
* 设置请求方式
* @param connection
* @param request
* @throws IOException
* @throws AuthFailureError
*/
/* package */
static void setConnectionParametersForRequest(HttpURLConnection connection,
Request<?> request) throws IOException, AuthFailureError {
switch (request.getMethod()) {
case Method.DEPRECATED_GET_OR_POST:
// This is the deprecated way that needs to be handled for backwards compatibility.
// If the request's post body is null, then the assumption is that the request is
// GET. Otherwise, it is assumed that the request is a POST.
byte[] postBody = request.getPostBody();
if (postBody != null) {
// Prepare output. There is no need to set Content-Length explicitly,
// since this is handled by HttpURLConnection using the size of the prepared
// output stream.
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.addRequestProperty(HEADER_CONTENT_TYPE,
request.getPostBodyContentType());
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.write(postBody);
out.close();
}
break;
case Method.GET:
// Not necessary to set the request method because connection defaults to GET but
// being explicit here.
connection.setRequestMethod("GET");
break;
case Method.DELETE:
connection.setRequestMethod("DELETE");
break;
case Method.POST:
connection.setRequestMethod("POST");
addBodyIfExists(connection, request);
break;
case Method.PUT:
connection.setRequestMethod("PUT");
addBodyIfExists(connection, request);
break;
case Method.HEAD:
connection.setRequestMethod("HEAD");
break;
case Method.OPTIONS:
connection.setRequestMethod("OPTIONS");
break;
case Method.TRACE:
connection.setRequestMethod("TRACE");
break;
case Method.PATCH:
connection.setRequestMethod("PATCH");
addBodyIfExists(connection, request);
break;
default:
throw new IllegalStateException("Unknown method type.");
}
}
最后获取响应,将响应头信息包装成StatusLine对象,再包装成BasicHttpResponse对象
StatusLine responseStatus = new BasicStatusLine(protocolVersion,
connection.getResponseCode(), connection.getResponseMessage());//响应状态类
BasicHttpResponse response = new BasicHttpResponse(responseStatus);
然后为BasicHttpResponse加入响应内容
response.setEntity(entityFromConnection(connection));//解析响应实体
entityFromConnection(HttpURLConnection connection)方法:
/**
* Initializes an {@link HttpEntity} from the given {@link HttpURLConnection}.
* <br>解析出响应实体
* @param connection
* @return an HttpEntity populated with data from <code>connection</code>.
*/
private static HttpEntity entityFromConnection(HttpURLConnection connection) {
BasicHttpEntity entity = new BasicHttpEntity();
InputStream inputStream;
try {
inputStream = connection.getInputStream();
} catch (IOException ioe) {
inputStream = connection.getErrorStream();
}
entity.setContent(inputStream);
entity.setContentLength(connection.getContentLength());
entity.setContentEncoding(connection.getContentEncoding());
entity.setContentType(connection.getContentType());
return entity;
}
最后,加入响应头部内容
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {//添加响应头
if (header.getKey() != null) {
Header h = new BasicHeader(header.getKey(), header.getValue().get(0));
response.addHeader(h);
}
}
OK,这样就返回了一个具有完整信息的HttpResponse对象。整个过程比较简单,是常规的网络请求内容。
2.HttpClientStack的实现,直接来看performRequest()方法
@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);
addHeaders(httpRequest, additionalHeaders);//添加缓存头
addHeaders(httpRequest, request.getHeaders());//添加请求头
onPrepareRequest(httpRequest);//请求预处理
HttpParams httpParams = httpRequest.getParams();
int timeoutMs = request.getTimeoutMs();
// TODO: Reevaluate this connection timeout based on more wide-scale
// data collection and possibly different for wifi vs. 3G.
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
return mClient.execute(httpRequest);
}
请求步骤,首先是根据请求方式,构造HttpUriRequest对象,并且设置请求参数
HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);
createHttpRequest()方法:
/**
* Creates the appropriate subclass of HttpUriRequest for passed in request.
* 根据请求方式返回对应HttpUriRequest的子类
*/
@SuppressWarnings("deprecation")
/* protected */
static HttpUriRequest createHttpRequest(Request<?> request,
Map<String, String> additionalHeaders) throws AuthFailureError {
switch (request.getMethod()) {
case Method.DEPRECATED_GET_OR_POST: {
// This is the deprecated way that needs to be handled for backwards compatibility.
// If the request's post body is null, then the assumption is that the request is
// GET. Otherwise, it is assumed that the request is a POST.
byte[] postBody = request.getPostBody();
if (postBody != null) {
HttpPost postRequest = new HttpPost(request.getUrl());
postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType());
HttpEntity entity;
entity = new ByteArrayEntity(postBody);
postRequest.setEntity(entity);
return postRequest;
} else {
return new HttpGet(request.getUrl());
}
}
case Method.GET:
return new HttpGet(request.getUrl());
case Method.DELETE:
return new HttpDelete(request.getUrl());
case Method.POST: {
HttpPost postRequest = new HttpPost(request.getUrl());
postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
setEntityIfNonEmptyBody(postRequest, request);//设置请求参数
return postRequest;
}
case Method.PUT: {
HttpPut putRequest = new HttpPut(request.getUrl());
putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
setEntityIfNonEmptyBody(putRequest, request);
return putRequest;
}
case Method.HEAD:
return new HttpHead(request.getUrl());
case Method.OPTIONS:
return new HttpOptions(request.getUrl());
case Method.TRACE:
return new HttpTrace(request.getUrl());
case Method.PATCH: {
HttpPatch patchRequest = new HttpPatch(request.getUrl());
patchRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
setEntityIfNonEmptyBody(patchRequest, request);
return patchRequest;
}
default:
throw new IllegalStateException("Unknown request method.");
}
}
从createHttpRequest()方法可以看出,在HttpClient中,只要根据请求方式,new一个HttpGet/HttpPost/….对象就可以了(而urlstack这一步是真的connnection而言的)
接着是为HttpUriRequest对象设置请求头部
addHeaders(httpRequest, additionalHeaders);//添加缓存头
addHeaders(httpRequest, request.getHeaders());//添加请求头
addHeaders方法:
/**
* 添加响应头
* @param httpRequest
* @param headers
*/
private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) {
for (String key : headers.keySet()) {
httpRequest.setHeader(key, headers.get(key));
}
}
最后,将HttpUriRequest对象交给httpClient执行
return mClient.execute(httpRequest);
3.HurlStack与HttpClientStack区别进行总结
OK,HttpClientStack比我们想象的还要简单,起码比HurlStack简单,这是当然的,因为使用httpClient方式,其本质就是对urlConnection的封装,然而这个封装并不是很完美,所以造成了版本之间的差异。
2. new RequestQueue(new DiskBasedCache(cacheDir), network)这里面的源码进行分析
我们点击跳转到这个构造方法中
//参数一:缓存 参数二:联网工作的状态
public RequestQueue(Cache cache, Network network) {
this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
}
当点击里面的那个this方法时候会跳转到如下构造函数中
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(cache, network, threadPoolSize,
new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}
通过分析我们可以发现,最后是将网络请求响应的数据发送到主线程进行操作的
3.queue.start(); 这个里面的方法中进行分析
public void start() {
//确保当前正在运行的调度程序已经停止
stop();
//参数一:实例化缓存分流队列
//参数二:实际化到达网络的请求队列
//参数三:用于检索和存储响应的高速缓存接口
//参数四:响应传递机制
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();
// Create network dispatchers (and corresponding threads) up to the pool size.
for (int i = 0; i < mDispatchers.length; i++) {
//参数一:实际化到达网络的请求队列
//参数二:用于检索和存储响应的高速缓存接口
//参数三:参数四:响应传递机制
NetworkDispatcher networkDispatcher = new
NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
CacheDispatcher是缓存调度线程,在调用start()方法。在循环中调用了NetworkDispatcher网络调度线程。默认情况下网络调度线程是4,缓存调度线程是一个,一共5个线程在后台运行并等待请求的到来。同时进行添加到请求到队列里面来。
接下来我们一起来看一下add()方法的源码进行分析
public <T> Request<T> add(Request<T> request) {
// 将此请求与指定的队列进行关联,当这个请求队列被通知
request.setRequestQueue(this);
synchronized (mCurrentRequests) {
mCurrentRequests.add(request);
}
// 按照添加的顺序处理请求
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");
// 如果不能缓存,将请求添加到网络请求队列中
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
// Insert request into stage if there's already a request with the same cache key in flight.
synchronized (mWaitingRequests) {
String cacheKey = request.getCacheKey();
//如果此前有相同的请求且还没有返回结果,就将次请求加入mWaitingRequests队列
if (mWaitingRequests.containsKey(cacheKey)) {
// 如果有已经在队列的请求,后面的进行等待
Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
if (stagedRequests == null) {
stagedRequests = new LinkedList<Request<?>>();
}
stagedRequests.add(request);
mWaitingRequests.put(cacheKey, stagedRequests);
if (VolleyLog.DEBUG) {
VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
}
} else {
// Insert 'null' queue for this cacheKey, indicating there is now a request in
// flight.
mWaitingRequests.put(cacheKey, null);
mCacheQueue.add(request);
}
return request;
}
}
代码分析:request.shouldCache()判断是否可以进行缓存的,默认是可以缓存的。如果不能缓存,则将请求添加到网络请求队列里面。如果能缓存,则判断之前是否有执行相同的请求且没有返回结果的,如果有的话将此请求加入到mWaitingRequests队列中,不再进行重复的请求,没有的话就请求加入到缓存的队列mCacheQueue.RequestQueue的add方法并没有请求网络或者对缓存的操作,当将请求添加到网络请求的队列或者缓存队列时,在后台的网络调度线程和缓存调度线程轮询各自的请求队列,若发现有请求任务则开始执行。
我们来看一下缓存调度线程CacheDispatcher
@Override
public void run() {
if (DEBUG) VolleyLog.v("start new dispatcher");
//线程优先级设置为*别
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// Make a blocking call to initialize the cache.
mCache.initialize();
Request<?> request;
while (true) {
// release previous request object to avoid leaking request object when mQueue is drained.
request = null;
try {
// 获取缓存队列中的一个请求
request = mCacheQueue.take();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
}
try {
request.addMarker("cache-queue-take");
// 如果请求取消,则将请求进行停止
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
continue;
}
// 查看是否有缓存的响应
Cache.Entry entry = mCache.get(request.getCacheKey());
//如果请求的缓存响应是空,将它添加到网络队列中
if (entry == null) {
request.addMarker("cache-miss");
// Cache miss; send off to the network dispatcher.
mNetworkQueue.put(request);
continue;
}
// 判断缓存的响应是否过期
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
mNetworkQueue.put(request);
continue;
}
// We have a cache hit; parse its data for delivery back to the request.
request.addMarker("cache-hit");
//对数据的解析并回调给主线程
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
if (!entry.refreshNeeded()) {
// Completely unexpired cache hit. Just deliver the response.
mDelivery.postResponse(request, response);
} else {
// Soft-expired cache hit. We can deliver the cached response,
// but we need to also send the request to the network for
// refreshing.
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// Mark the response as intermediate.
response.intermediate = true;
// Post the intermediate response back to the user and have
// the delivery then forward the request along to the network.
final Request<?> finalRequest = request;
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(finalRequest);
} catch (InterruptedException e) {
// Not much we can do about this.
}
}
});
}
} catch (Exception e) {
VolleyLog.e(e, "Unhandled exception %s", e.toString());
}
}
}
分析:首先从缓存队列取出请求,判断请求是否取消,如果请求没有被取消则判断是否有缓存的响应,如果有缓存的响应。如果有缓存的响应并且没有过期,则对缓存响应进行解析并回调给主线程:如果没有缓存的响应,则将请求添加到网络调度线程
网络调度线程NetworkDispatcher
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Request<?> request;
while (true) {
long startTimeMs = SystemClock.elapsedRealtime();
// release previous request object to avoid leaking request object when mQueue is drained.
request = null;
try {
// 从队列中取出请求
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.
// 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);
}
}
}
这个网络调度线程和缓存调度线程处理的逻辑几乎相同,在这里,不做过多的介绍了,mNetwork.performRequest(request);我们可以观察到这个里面是个接口,实现类是BasicNetwork,我们来接着往下进行分析
1.Network接口类代码如下
public interface Network {
/**
* Performs the specified request.执行这个请求
* @param request Request to process//待处理的请求
* @return A {@link NetworkResponse} with data and caching metadata; will never be null
* 返回一个请求结果,不会为空
* @throws VolleyError on errors
*/
public NetworkResponse performRequest(Request<?> request) throws VolleyError;
}
2.BasicNetwork中的performRequest里面的请求进行分析
/**
* @title performRequest执行各种Request请求并以NetworkResponse的形式返回结果
* @param Request
* @return NetworkResponse
* @throws VolleyError
* 定义:{@link Network#performRequest(Request)}
* 被调:{@link NetworkDispatcher#run()}
*
*/
@Override//NetworkDispatcher的run()方法中调用
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();//开始请求时间
while (true) {
HttpResponse httpResponse = null;//apache的请求结果
byte[] responseContents = null;//请求的内容
Map<String, String> responseHeaders = new HashMap<String, String>();//响应结果头部信息
try {
// Gather headers.
Map<String, String> headers = new HashMap<String, String>();//保存缓存数据
addCacheHeaders(headers, request.getCacheEntry());//先获取缓存数据
httpResponse = mHttpStack.performRequest(request, headers);//去调用mHttpStack的实现方法执行请求
StatusLine statusLine = httpResponse.getStatusLine();//获取http状态线
int statusCode = statusLine.getStatusCode();//获取状态码
responseHeaders = convertHeaders(httpResponse.getAllHeaders());
// Handle cache validation.//处理缓存验证
if (statusCode == HttpStatus.SC_NOT_MODIFIED) {//返回缓存数据
return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,
request.getCacheEntry().data, responseHeaders, true);
}
//把HttpEntity转化为byte[]数据
responseContents = entityToBytes(httpResponse.getEntity());
// if the request is slow, log it.//如果请求很慢,就打印出来看一下
long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
logSlowRequests(requestLifetime, request, responseContents, statusLine);//打印
//连接正常但是返回无内容,抛出IO异常
if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_NO_CONTENT) {
throw new IOException();
}
return new NetworkResponse(statusCode, responseContents, responseHeaders, false);
} catch (SocketTimeoutException e) {//读取超时,重试
attemptRetryOnException("socket", request, new TimeoutError());
} catch (ConnectTimeoutException e) {//连接超时,重试
attemptRetryOnException("connection", request, new TimeoutError());
} catch (MalformedURLException e) {//Bad URL
throw new RuntimeException("Bad URL " + request.getUrl(), e);
} catch (IOException e) {//IO异常
int statusCode = 0;
NetworkResponse networkResponse = null;
if (httpResponse != null) {
statusCode = httpResponse.getStatusLine().getStatusCode();
} else {//如果没有返回httpResponse,就说明没连接
throw new NoConnectionError(e);
}
VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
if (responseContents != null) {//返回数据不为空
networkResponse = new NetworkResponse(statusCode, responseContents,
responseHeaders, false);//创建响应体
if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
statusCode == HttpStatus.SC_FORBIDDEN) {//认证失败异常,重试
attemptRetryOnException("auth",
request, new AuthFailureError(networkResponse));
} else {//服务器异常
// TODO: Only throw ServerError for 5xx status codes.
throw new ServerError(networkResponse);//只有状态码为5XX才抛出服务器异常
}
} else {//网络异常
throw new NetworkError(networkResponse);
}
}
}
}
代码解析:
1.先是通过mHttpStack把请求执行并且获取它的响应结果,根据HttpStatus做出各种判断。
2.然后再把httpResponse的Entity转化为ByteArray,并处理各种发生的异常。
3.最后的过程是这样的:通过Volley创建一个RequestQueue请求队列,当这个队列开始运作的时候会启动NetworkDispatcher这个工作线程,而BasicNetwork的performRequest()的方法就在NetworkDispatcher线程run()方法中调用,然后通过mHttpStack的performRequest()方法获取一个networkResponse,在NetworkDispatcher线程把这个networkResponse转化为期望的数据类型,比如Response<String>,Response<Json>,Response<Bitmap>。
3. mDelivery.postResponse(request, response);
@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
request.markDelivered();
request.addMarker("post-response");
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
}
4.ResponseDeliveryRunnable我们来看一下这里面都做了什么处理的
/**
* 在主线程进行返回一个网络响应的交付线程
*/
@SuppressWarnings("rawtypes")
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;
}
@SuppressWarnings("unchecked")
@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();
}
}
}
Volley源码分析结束。
上一篇: 详解如何在 Docker 中设置 Go 并部署应用
下一篇: java lambda错误用法