剖析Volley请求多次的原理

转载地址剖析Volley请求多次的原理

网络线程NetWorkDispather 的run 方法里有一行代码:NetworkResponse networkResponse = mNetwork.performRequest(request);意思开始请求服务端,直到返回响应,进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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
   public  NetworkResponse performRequest(Request<?> request)  throws  VolleyError {
         long  requestStart = SystemClock.elapsedRealtime();
         while  ( true ) {
             HttpResponse httpResponse =  null ;
             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());
1                 httpResponse = mHttpStack.performRequest(request, headers);
                 StatusLine statusLine = httpResponse.getStatusLine();
                 int  statusCode = statusLine.getStatusCode();
 
                 responseHeaders = convertHeaders(httpResponse.getAllHeaders());
                 // Handle cache validation.
2                 if  (statusCode == HttpStatus.SC_NOT_MODIFIED) {
                     return  new  NetworkResponse(HttpStatus.SC_NOT_MODIFIED,
                             request.getCacheEntry() ==  null  null  : request.getCacheEntry().data,
                             responseHeaders,  true );
                 }
 
                 // Some responses such as 204s do not have content.  We must check.
                 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 ];
                 }
 
                 // if the request is slow, log it.
                 long  requestLifetime = SystemClock.elapsedRealtime() - requestStart;
                 logSlowRequests(requestLifetime, request, responseContents, statusLine);
 
                 if  (statusCode <  200  || statusCode >  299 ) {
                     throw  new  IOException();
                 }
3                 return  new  NetworkResponse(statusCode, responseContents, responseHeaders,  false );
             catch  (SocketTimeoutException e) {
4                 attemptRetryOnException( "socket" , request,  new  TimeoutError());
             catch  (ConnectTimeoutException e) {
5                 attemptRetryOnException( "connection" , request,  new  TimeoutError());
             catch  (MalformedURLException e) {
6                 throw  new  RuntimeException( "Bad URL "  + request.getUrl(), e);
             catch  (IOException e) {
                 int  statusCode =  0 ;
                 NetworkResponse networkResponse =  null ;
                 if  (httpResponse !=  null ) {
                     statusCode = httpResponse.getStatusLine().getStatusCode();
                 else  {
                     throw  new  NoConnectionError(e);
                 }
                 VolleyLog.e( "Unexpected response code %d for %s" , statusCode, request.getUrl());
7                 if  (responseContents !=  null ) {
8                     networkResponse =  new  NetworkResponse(statusCode, responseContents,
                             responseHeaders,  false );
                     if  (statusCode == HttpStatus.SC_UNAUTHORIZED ||
                             statusCode == HttpStatus.SC_FORBIDDEN) {
9                         attemptRetryOnException( "auth" ,
                                 request,  new  AuthFailureError(networkResponse));
                     else  {
                         // TODO: Only throw ServerError for 5xx status codes.
                         throw  new  ServerError(networkResponse);
                     }
                 else  {
                     throw  new  NetworkError(networkResponse);
                 }
             }
         }
     }

这个方法代码有点长,但结构很清晰,循环执行这个请求,直到收到服务端响应,或者抛出异常。1处传请求内容和请求头,http通信,直到返回一个HttpResponose对象,解析这个对象,2,3处返回结果。上述是正常的请求返回过程,如果这个过程发生了异常并且被捕获,执行重发或者抛出异常。4,5处看到调用的方法的签名可猜到尝试重新请求,这是捕获的异常都是超时异常。进到attempRetryException看看:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  private  static  void  attemptRetryOnException(String logPrefix, Request<?> request,
             VolleyError exception)  throws  VolleyError {
         RetryPolicy retryPolicy = request.getRetryPolicy();
         int  oldTimeout = request.getTimeoutMs();
 
         try  {
1             retryPolicy.retry(exception);
         catch  (VolleyError e) {
             request.addMarker(
                     String.format( "%s-timeout-giveup [timeout=%s]" , logPrefix, oldTimeout));
             throw  e;
         }
         request.addMarker(String.format( "%s-retry [timeout=%s]" , logPrefix, oldTimeout));
     }

这个方法的逻辑也简单,只要不抛出异常,就正常执行,判断是否抛异常就看1处,进retry方法看看

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
   public  void  retry(VolleyError error)  throws  VolleyError {
         mCurrentRetryCount++;
         mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);
1         if  (!hasAttemptRemaining()) {
             throw  error;
         }
     }
 
     /**
      * Returns true if this policy has attempts remaining, false otherwise.
      */
     protected  boolean  hasAttemptRemaining() {
2         return  mCurrentRetryCount <= mMaxNumRetries;
     }

关键在hasAttempRemaining()方法,先mCurrentRetryCount++,然后和mMaxNumRetries比较,这里的逻辑的意思是当前尝试请求的次数大于最大请求数就抛出异常,这样逻辑回到performRequest(),接着跳出循环,返回到网络线程,有网络线程处理抛出的异常。如果当前尝试请求的次数小于最大请求数,不抛出异常,逻辑回到performRequest(),接着下一次循环,再次尝试请求服务。在performRequest()的6处,说明请求url有问题,可能不合法,直接抛出RuntimeException异常返回网络线程。在performRequest()的7处,说明此时抛出了IO异常,在responseContents不为空的情况下,再次构造响应实例networkResponse,如果是认证问题的话,再给重新请求的机会,逻辑就走到attempRetryException(),只不过要抛出的异常是authFailureException,除了这个情况,其他情况都抛出异常返回网络线程,处理异常。这样我们分析了请求多次的原理,但又有疑问,在这个请求多次怎么设置它的次数呢,在刚才对attempRetryException的分析中发现,判断次数是否超出的逻辑是在一个叫DefaultRetryPolicy的类里面实现的,在request可以直接传一个DefaultRetryPolicy的实例进去,具体的代码是


= JsonPostRequest(IMConfig.map).setRetryPolicy(DefaultRetryPolicy(DefaultRetryPolicy.* DefaultRetryPolicy.DefaultRetryPolicy.))

关注DefaultRetryPolicy的构造方法第二个参数,就是指定请求多少次的最大数。另外两个参数是计算超时时间的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值