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

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

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

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

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

BasicNetwork做的事情如下:

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void addCacheHeaders(Map<string, string= "" > headers, Cache.Entry entry) {
     // If there's no cache entry, we're done.
     if (entry == null ) {
         return ;
     }
 
     if (entry.etag != null ) {
         headers.put( "If-None-Match" , entry.etag);
     }
 
     if (entry.serverDate > 0 ) {
         Date refTime = new Date(entry.serverDate);
         headers.put( "If-Modified-Since" , DateUtils.formatDate(refTime));
     }
}</string,>

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

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

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


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

结束!

关于缓存线程的介绍:

Android中关于Volley的使用(六)认识 CacheDispatcher

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值