[关闭]
@946898963 2018-05-18T11:51:54.000000Z 字数 6974 阅读 1042

Volley-Network及其实现类的源码解析

Android控件跟框架 Android源码分析


Network也是一个接口,它只包含一个方法,表示处理网络请求并返回处理结果:

  1. public NetworkResponse performRequest(Request<?> request) throws VolleyError;

此处输入图片的描述

Network有一个唯一实现类BasicNetwork。BasicNetwork使用HttpStack执行网络请求,成功后返回一个NetworkResponse,NetworkResponse只是一个简单的记录状态码,body,响应头,服务端是否返回304并且缓存过,执行网络请求时间的类。

首先看下他的构造方法:

  1. /**
  2. * 带一个默认大小的ByteArrayPool缓冲池
  3. * @param httpStack HTTP stack to be used
  4. */
  5. public BasicNetwork(HttpStack httpStack) {
  6. // If a pool isn't passed in, then build a small default pool that will give us a lot of
  7. // benefit and not use too much memory.
  8. //如果一个池没有通过,将建立一个小的默认缓存池,这样会给我们带来很大的益处,不需要耗费很多内存
  9. this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));
  10. }
  11. /**
  12. * 主构造方法BasicNetwork(HttpStack*,ByteArrayPool*)
  13. * @param httpStack HTTP stack to be used
  14. * @param pool a buffer pool that improves GC performance in copy operations
  15. */
  16. public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) {
  17. mHttpStack = httpStack;
  18. mPool = pool;
  19. }

有两个参数HttpStack和ByteArrayPool,这两个参数就是主要的成员变量。关于HttpStack和ByteArrayPool,建议阅读:HttpStack及其实现类源码解析&&ByteArrayPool源码解析
BasicNetwork实现了NetWork接口的performRequest方法,我们来看下这个方法的具体实现:

  1. /**
  2. * @title performRequest执行各种Request请求并以NetworkResponse的形式返回结果
  3. * @param Request
  4. * @return NetworkResponse
  5. * @throws VolleyError
  6. * 定义:{@link Network#performRequest(Request)}
  7. * 被调:{@link NetworkDispatcher#run()}
  8. *
  9. */
  10. @Override//NetworkDispatcher的run()方法中调用
  11. public NetworkResponse performRequest(Request<?> request) throws VolleyError {
  12. long requestStart = SystemClock.elapsedRealtime();//开始请求时间
  13. while (true) {
  14. HttpResponse httpResponse = null;//apache的请求结果
  15. byte[] responseContents = null;//请求的内容
  16. Map<String, String> responseHeaders = new HashMap<String, String>();//响应结果头部信息
  17. try {
  18. // Gather headers.
  19. Map<String, String> headers = new HashMap<String, String>();//保存缓存数据
  20. addCacheHeaders(headers, request.getCacheEntry());//先获取缓存数据
  21. httpResponse = mHttpStack.performRequest(request, headers);//去调用mHttpStack的实现方法执行请求
  22. StatusLine statusLine = httpResponse.getStatusLine();//获取http状态线
  23. int statusCode = statusLine.getStatusCode();//获取状态码
  24. responseHeaders = convertHeaders(httpResponse.getAllHeaders());
  25. // Handle cache validation.//处理缓存验证
  26. if (statusCode == HttpStatus.SC_NOT_MODIFIED) {//返回缓存数据
  27. return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,
  28. request.getCacheEntry().data, responseHeaders, true);
  29. }
  30. //把HttpEntity转化为byte[]数据
  31. responseContents = entityToBytes(httpResponse.getEntity());
  32. // if the request is slow, log it.//如果请求很慢,就打印出来看一下
  33. long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
  34. logSlowRequests(requestLifetime, request, responseContents, statusLine);//打印
  35. //连接正常但是返回无内容,抛出IO异常
  36. if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_NO_CONTENT) {
  37. throw new IOException();
  38. }
  39. return new NetworkResponse(statusCode, responseContents, responseHeaders, false);
  40. } catch (SocketTimeoutException e) {//读取超时,重试
  41. attemptRetryOnException("socket", request, new TimeoutError());
  42. } catch (ConnectTimeoutException e) {//连接超时,重试
  43. attemptRetryOnException("connection", request, new TimeoutError());
  44. } catch (MalformedURLException e) {//Bad URL
  45. throw new RuntimeException("Bad URL " + request.getUrl(), e);
  46. } catch (IOException e) {//IO异常
  47. int statusCode = 0;
  48. NetworkResponse networkResponse = null;
  49. if (httpResponse != null) {
  50. statusCode = httpResponse.getStatusLine().getStatusCode();
  51. } else {//如果没有返回httpResponse,就说明没连接
  52. throw new NoConnectionError(e);
  53. }
  54. VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
  55. if (responseContents != null) {//返回数据不为空
  56. networkResponse = new NetworkResponse(statusCode, responseContents,
  57. responseHeaders, false);//创建响应体
  58. if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
  59. statusCode == HttpStatus.SC_FORBIDDEN) {//认证失败异常,重试
  60. attemptRetryOnException("auth",
  61. request, new AuthFailureError(networkResponse));
  62. } else {//服务器异常
  63. // TODO: Only throw ServerError for 5xx status codes.
  64. throw new ServerError(networkResponse);//只有状态码为5XX才抛出服务器异常
  65. }
  66. } else {//网络异常
  67. throw new NetworkError(networkResponse);
  68. }
  69. }
  70. }
  71. }

performRequest方法中,使用到了一个while循环,之所以使用while循环,是为了当出错的时候进行重试,关于重试策略,建议阅读:Volley的请求重试策略相关源码分析。看下while循环中的代码:
A. 获取和设置与条件请求相关的首部信息。

  1. Map<String, String> headers = new HashMap<String, String>();//保存缓存数据
  2. addCacheHeaders(headers, request.getCacheEntry());//先获取缓存数据
  1. private void addCacheHeaders(Map<String, String> headers, Cache.Entry entry) {
  2. // If there's no cache entry, we're done.
  3. if (entry == null) {
  4. return;
  5. }
  6. if (entry.etag != null) {
  7. headers.put("If-None-Match", entry.etag);
  8. }
  9. if (entry.lastModified > 0) {
  10. Date refTime = new Date(entry.lastModified);
  11. headers.put("If-Modified-Since", DateUtils.formatDate(refTime));
  12. }
  13. }

从代码中可以看到,如果request.getCacheEntry()不为空,这时候会在设置请求首部的map中添加"If-None-Match"首部和"If-Modified-Since"首部,其值分别为缓存数据的etag和lastModified,"If-None-Match"和"If-Modified-Since"这两个首部是用来进行条件请求的,设置了这两个首部后,发起的请求就是条件请求。
注意在默认的情况下request.getCacheEntry()返回的是null,只有当请求存在缓存数据,但是缓存数据过期的情况下,request.getCacheEntry()才不会为空,具体的实现是在CacheDispatcher的run方法中。在run方法中当获取到本地的缓存,但是本地缓存数据过期的时候,会将本地缓存的数据(首部信息和实体信息)放到Request中,然后将请求放入请求队列中,等待处理。

CacheDispatcher的run方法:

  1. @Override
  2. public void run() {
  3. ....
  4. while (true) {
  5. try {
  6. ....
  7. Cache.Entry entry = mCache.get(request.getCacheKey());
  8. if (entry == null) {
  9. request.addMarker("cache-miss");
  10. // Cache miss; send off to the network dispatcher.
  11. mNetworkQueue.put(request);
  12. continue;
  13. }
  14. if (entry.isExpired()) {
  15. request.addMarker("cache-hit-expired");
  16. request.setCacheEntry(entry);
  17. mNetworkQueue.put(request);
  18. continue;
  19. }
  20. ....
  21. }
  22. }

B. 调用传入的HttpStack的performRequest方法去执行请求,并将响应结果封装成一个HttpResponse。

  1. httpResponse = mHttpStack.performRequest(request,headers);//去调用mHttpStack的实现方法执行请求

C. 获取响应结果的状态码和响应的首部信息,然后根据响应结果的状态码,进行相关的操作。
如果状态码是304,则直接使用本地的缓存数据和响应的首部信息,构造NetworkResponse并返回。

  1. StatusLine statusLine = httpResponse.getStatusLine();//获取http状态线
  2. int statusCode = statusLine.getStatusCode();//获取状态码
  3. responseHeaders = convertHeaders(httpResponse.getAllHeaders());
  4. // Handle cache validation.//处理缓存验证
  5. if (statusCode == HttpStatus.SC_NOT_MODIFIED) {//返回缓存数据
  6. return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,request.getCacheEntry().data,responseHeaders, true);
  7. }
  1. protected static Map<String, String> convertHeaders(Header[] headers) {
  2. Map<String, String> result = new TreeMap<String,String>(String.CASE_INSENSITIVE_ORDER);
  3. for (int i = 0; i < headers.length; i++) {
  4. result.put(headers[i].getName(), headers[i].getValue());
  5. }
  6. return result;
  7. }

如果状态码不是304,说明可能有数据返回,获取响应实体,然后解析响应实体的内容,获得byte[]数组,利用获取到的byte[]数组和响应的首部信息,构造NetworkResponse并返回。

  1. responseContents = entityToBytes(httpResponse.getEntity());
  2. return new NetworkResponse(statusCode, responseContents, responseHeaders, false);
  1. private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError {
  2. PoolingByteArrayOutputStream bytes = new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength());
  3. byte[] buffer = null;
  4. try {
  5. InputStream in = entity.getContent();
  6. if (in == null) {
  7. throw new ServerError();
  8. }
  9. buffer = mPool.getBuf(1024);
  10. int count;
  11. while ((count = in.read(buffer)) != -1) {
  12. bytes.write(buffer, 0, count);
  13. }
  14. return bytes.toByteArray();
  15. } finally {
  16. try {
  17. // Close the InputStream and release the resources by "consuming the content".
  18. entity.consumeContent();
  19. } catch (IOException e) {
  20. // This can happen if there was an exception above that left the entity in
  21. // an invalid state.
  22. VolleyLog.v("Error occured when calling consumingContent");
  23. }
  24. mPool.returnBuf(buffer);
  25. bytes.close();
  26. }
  27. }

这里用到了PoolingByteArrayOutputStream,关于PoolingByteArrayOutputStream,建议阅读:PoolingByteArrayOutputStream源码解析
D. 当出现异常的时候,进行相关的操作,这里主要关心Volley的重试策略,建议阅读:Volley的请求重试策略相关源码分析

参考链接:

谷歌Volley网络框架讲解——Network及其实现类

Http status code : 304
HTTP状态码

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注