Android中关于Volley的使用(四)认识 NetworkDispatcher 和 BasicNetwork

Volley最主要的功能其实就是跟网络打交道,然后从网络中获取相对应的数据,虽然有缓存线程(CacheDispatcher),但是如果缓存中没有对应的记录的话,还是会将其扔到网络队列中,由网络线程(NetworkDispatcher)来干活。

那么就看看NetworkDispatcher都干什么吧,如下:

[java]  view plain copy
  1. public void run() {  
  2.     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
  3.     Request<?> request;  
  4.     while (true) {  
  5.         try {  
  6.             // 从队列中获取一个请求,如果没有请求,则会一直阻塞  
  7.             request = mQueue.take();  
  8.         } catch (InterruptedException e) {  
  9.             // We may have been interrupted because it was time to quit.  
  10.             if (mQuit) {  
  11.                 return;  
  12.             }  
  13.             continue;  
  14.         }  
  15.   
  16.         try {  
  17.             request.addMarker("network-queue-take");  
  18.   
  19.             // 判断请求有没有取消,如果取消,则不必再继续  
  20.             if (request.isCanceled()) {  
  21.                 request.finish("network-discard-cancelled");  
  22.                 continue;  
  23.             }  
  24.   
  25.             addTrafficStatsTag(request);  
  26.   
  27.             // 调用mNetwork去跟网络打交道  
  28.             NetworkResponse networkResponse = mNetwork.performRequest(request);  
  29.             request.addMarker("network-http-complete");  
  30.   
  31.             // 如果服务器返回一个未修改(304)的响应,并且这个请求已经发送过响应对象,不需要再继续,因为没改过  
  32.             if (networkResponse.notModified && request.hasHadResponseDelivered()) {  
  33.                 request.finish("not-modified");  
  34.                 continue;  
  35.             }  
  36.   
  37.             // 分析响应的数据,返回Response对象  
  38.             Response<?> response = request.parseNetworkResponse(networkResponse);  
  39.             request.addMarker("network-parse-complete");  
  40.   
  41.             // 根据request的shouldCache字段来判断是不是需要缓存,如果需要,则将其放到mCache中。  
  42.             if (request.shouldCache() && response.cacheEntry != null) {  
  43.                 mCache.put(request.getCacheKey(), response.cacheEntry);  
  44.                 request.addMarker("network-cache-written");  
  45.             }  
  46.   
  47.             // 调用 mDelivery将Response对象传回主线程进行UI的更新。  
  48.             request.markDelivered();  
  49.             mDelivery.postResponse(request, response);  
  50.         } catch (VolleyError volleyError) {  
  51.             parseAndDeliverNetworkError(request, volleyError);//有错误,也会调用到mDelivery,将错误信息传回到主线程,进行提示  
  52.         } catch (Exception e) {  
  53.             VolleyLog.e(e, "Unhandled exception %s", e.toString());  
  54.             mDelivery.postError(request, new VolleyError(e));  
  55.         }  
  56.     }  
  57. }  
网络线程(NetworkDispatcher)主要做了几件事情:

1)调用 mQueue的take()方法从队列中获取请求,如果没有请求,则一直阻塞在那里等待,直到队列中有新的请求到来。

2)判断请求有没有被取消,如果被取消,则重新获取请求。

3)调用Network对象将请求发送到网络中,并返回一个 NetworkResponse对象。

4)调用请求的pareseNetworkResonse方法,将NetworkResponse对象解析成相对应的Response对象。

5)判断请求是否需要缓存,如果需要缓存,则将其Response中cacheEntry对象放到缓存mCache中。

6)调用 mDelivery将Response对象传到主线程中进行UI更新。

另外有一个要注意的就是,在Volley中,默认是有4个网络线程同时在跑的,而对应的缓存线程,则只有一个。

从上面的代码中,可以看到,网络线程其实是调用 Network对象去实现跟网络进行沟通的,而在Volley中,默认的Network实现类,则是BasicNetwork类。

下面我们就看看它的performRequest方法:

[java]  view plain copy
  1. public NetworkResponse performRequest(Request<?> request) throws VolleyError {  
  2.      ...  
  3.      while (true) {  
  4.          HttpResponse httpResponse = null;  
  5.          byte[] responseContents = null;  
  6.          Map<String, String> responseHeaders = new HashMap<String, String>();  
  7.          try {  
  8.              // 添加头部信息  
  9.              Map<String, String> headers = new HashMap<String, String>();  
  10.              addCacheHeaders(headers, request.getCacheEntry());  
  11.              httpResponse = mHttpStack.performRequest(request, headers);//调用HttpStack对象去网络中获取数据  
  12.              StatusLine statusLine = httpResponse.getStatusLine();  
  13.              int statusCode = statusLine.getStatusCode();  
  14.   
  15.              responseHeaders = convertHeaders(httpResponse.getAllHeaders());  
  16.              // 从响应的状态行获取状态编码,如果是304(未修改),说明之前已经取过数据了,那么就直接利用缓存中的数据,构造一个NetworkResonse对象  
  17.              if (statusCode == HttpStatus.SC_NOT_MODIFIED) {  
  18.                  return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,  
  19.                          request.getCacheEntry() == null ? null : request.getCacheEntry().data,  
  20.                          responseHeaders, true);  
  21.              }  
  22.   
  23.              // 有些响应是不带内容的,比如响应状态编码是204的话,添加一个空的byte作为内容,后面好统一处理。  
  24.              if (httpResponse.getEntity() != null) {  
  25.                responseContents = entityToBytes(httpResponse.getEntity());  
  26.              } else {  
  27.                // Add 0 byte response as a way of honestly representing a  
  28.                // no-content request.  
  29.                responseContents = new byte[0];  
  30.              }  
  31.              ...//忽略了一些log的处理。  
  32.              return new NetworkResponse(statusCode, responseContents, responseHeaders, false);  
  33.          } ...//这里忽略了一些异常处理  
  34.          } catch (IOException e) {  
  35.              ...  
  36.              if (responseContents != null) {  
  37.                  networkResponse = new NetworkResponse(statusCode, responseContents,  
  38.                          responseHeaders, false);  
  39.                  if (statusCode == HttpStatus.SC_UNAUTHORIZED ||  
  40.                          statusCode == HttpStatus.SC_FORBIDDEN) {  
  41.                      attemptRetryOnException("auth",  
  42.                              request, new AuthFailureError(networkResponse));//这里会根据Volley的Retyr机制进行重新获取。  
  43.                  } else {  
  44.                      throw new ServerError(networkResponse);  
  45.                  }  
  46.              } else {  
  47.                  throw new NetworkError(networkResponse);  
  48.              }  
  49.          }  
  50.      }  
  51.  }  

BasicNetwork做的事情如下:

1)对于已经有缓存的请求,添加其头部信息,如下:

[java]  view plain copy
  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.   
  7.     if (entry.etag != null) {  
  8.         headers.put("If-None-Match", entry.etag);  
  9.     }  
  10.   
  11.     if (entry.serverDate > 0) {  
  12.         Date refTime = new Date(entry.serverDate);  
  13.         headers.put("If-Modified-Since", DateUtils.formatDate(refTime));  
  14.     }  
  15. }  

2)调用 HttpStack 对象去网络中获取数据,返回httpResonse 对象。

3)根据状态编码来返回不同的Response对象,如304(未修改)就返回缓存中的数据,如果不是,则根据响应中的数据,重新构造一个NetworkResponse对象。

4)BasicNetwork实现了重试的机制,如果第一次从网络获取失败,默认会重新再尝试一次,如果失败,则会将Error返回,默认的实现类是DefaultRetryPolicy类。


在Network中返回的NetworkResponse对象,会在NetworkDispatcher中由具体的Request(比如ImageRequest,JsonRequest)类来进行解析,再最后返回给UI线程。

你可能感兴趣的:(Android中关于Volley的使用(四)认识 NetworkDispatcher 和 BasicNetwork)