• Android开源项目xUtils HttpUtils模块分析(转)


    xUtils是github上的一个Android开源工具项目,其中HttpUtils模块是处理网络连接部分,刚好最近想整理下Android网络编程知识,今天学习下xUtils中HttpUtils.

    xUtils项目地址:  https://github.com/wyouflf/xUtils

    先看看分析的时序图,了解下基本的过程

     

    1. Activity创建HttpUtils对象

    1 HttpUtils http = new HttpUtils();

    查看HttpUtils类的构造函数

     1 public HttpUtils() {
     2     this(HttpUtils.DEFAULT_CONN_TIMEOUT);
     3   }
     4 
     5   public HttpUtils(int connTimeout) {
     6     HttpParams params = new BasicHttpParams();
     7 
     8     ConnManagerParams.setTimeout(params, connTimeout);
     9     HttpConnectionParams.setSoTimeout(params, connTimeout);
    10     HttpConnectionParams.setConnectionTimeout(params, connTimeout);
    11 
    12     ConnManagerParams.setMaxConnectionsPerRoute(params, new ConnPerRouteBean(10));
    13     ConnManagerParams.setMaxTotalConnections(params, 10);
    14 
    15     HttpConnectionParams.setTcpNoDelay(params, true);
    16     HttpConnectionParams.setSocketBufferSize(params, 1024 * 8);
    17     HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
    18 
    19     SchemeRegistry schemeRegistry = new SchemeRegistry();
    20     schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    21     schemeRegistry.register(new Scheme("https", DefaultSSLSocketFactory.getSocketFactory(), 443));
    22 
    23     httpClient = new DefaultHttpClient(new ThreadSafeClientConnManager(params, schemeRegistry), params);
    24 
    25     httpClient.setHttpRequestRetryHandler(new RetryHandler(DEFAULT_RETRY_TIMES));
    26 
    27     httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
    28       @Override
    29       public void process(org.apache.http.HttpRequest httpRequest, HttpContext httpContext) throws org.apache.http.HttpException, IOException {
    30         if (!httpRequest.containsHeader(HEADER_ACCEPT_ENCODING)) {
    31           httpRequest.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
    32         }
    33       }
    34     });
    35 
    36     httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
    37       @Override
    38       public void process(HttpResponse response, HttpContext httpContext) throws org.apache.http.HttpException, IOException {
    39         final HttpEntity entity = response.getEntity();
    40         if (entity == null) {
    41           return;
    42         }
    43         final Header encoding = entity.getContentEncoding();
    44         if (encoding != null) {
    45           for (HeaderElement element : encoding.getElements()) {
    46             if (element.getName().equalsIgnoreCase("gzip")) {
    47               response.setEntity(new GZipDecompressingEntity(response.getEntity()));
    48               return;
    49             }
    50           }
    51         }
    52       }
    53     });
    54   }

    这里主要是设置HttpParams参数,然后创建httpClient对象。 

    注意这个类ThreadSafeClientConnManager,它主要是为了使用线程安全的连接管理来创建HttpClient。

    不过这里就有个疑问了,之前看资料了解到一般创建HttpClient都是用的 单例模式,说是一个httpClient就相当于是一个小型的浏览器,如果创建多个httpClient就很消耗资源了,我看了这个开源项目给的demo,是创建一个请求就创建一个HttpClient, 到时跟作者联系看看是什么回事。

    2.发送请求

     1  http.send(HttpRequest.HttpMethod.GET,
     2         "http://www.baidu.com",
     3         new RequestCallBack<String>() {
     4 
     5 
     6           @Override
     7           public void onStart() {
     8             resultText.setText("conn...");
     9           }
    10 
    11 
    12           @Override
    13           public void onLoading(long total, long current, boolean isUploading) {
    14             resultText.setText(current + "/" + total);
    15           }
    16 
    17 
    18           @Override
    19           public void onSuccess(ResponseInfo<String> responseInfo) {
    20             resultText.setText("response:" + responseInfo.result);
    21           }
    22 
    23 
    24 
    25 
    26           @Override
    27           public void onFailure(HttpException error, String msg) {
    28             resultText.setText(msg);
    29           }
    30         });

    调用send方法发生请求, 

    HttpRequest.HttpMethod.GET指明请求的方式,

    "http://www.baidu.com"请求的地址,

    new RequestCallBack<String>()请求的回调函数,这里面四个方法方便开发者处理请求的各个阶段的结果。

    3. http.send()

     1 public <T> HttpHandler<T> send(HttpRequest.HttpMethod method, String url,
     2            RequestCallBack<T> callBack) {
     3   return send(method, url, null, callBack);
     4     }
     5 
     6     public <T> HttpHandler<T> send(HttpRequest.HttpMethod method, String url, RequestParams params,
     7            RequestCallBack<T> callBack) {
     8   if (url == null) throw new IllegalArgumentException("url may not be null");
     9 
    10   HttpRequest request = new HttpRequest(method, url);
    11   return sendRequest(request, params, callBack);
    12     }
    13     private <T> HttpHandler<T> sendRequest(HttpRequest request, RequestParams params, RequestCallBack<T> callBack) {
    14 
    15   HttpHandler<T> handler = new HttpHandler<T>(httpClient, httpContext, responseTextCharset, callBack);
    16 
    17   handler.setExpiry(currentRequestExpiry);
    18   handler.setHttpRedirectHandler(httpRedirectHandler);
    19   request.setRequestParams(params, handler);
    20 
    21   handler.executeOnExecutor(executor, request);
    22   return handler;
    23     }

    查看httpUtils的send函数,发现最后会调用sendRequest函数 

    在sendRequest里创建HttpHandler对象

    4. HttpHandler

    1 HttpHandler<T> extends CompatibleAsyncTask<Object, Object, Void> implements RequestCallBackHandler

    参看httpHandler发现它继承CompatibleAsyncTask

    5.CompatibleAsyncTask

    查看CompatibleAsyncTask ,发现它是A compatible AsyncTask for android2.2.你懂得  

    6.handler.executeOnExecutor(executor, request)

    在第3步里创建完httpHandler后,调用handler.executeOnExecutor(executor, request),而通过第4步了解到httpHandler继承CompatiableAsyncTask, 就先去看看doInBackground里做了什么事情。

    7.doInBackground(Object... params)

     1 //先处理传递进来的params
     2   
     3   this.publishProgress(UPDATE_START);
     4 
     5 
     6   lastUpdateTime = SystemClock.uptimeMillis();
     7 
     8 
     9   ResponseInfo<T> responseInfo = sendRequest(request);
    10   if (responseInfo != null) {
    11       this.publishProgress(UPDATE_SUCCESS, responseInfo);
    12       return null;
    13   }

    先处理传递进来的params,调用publishProgress更新下当前的状态,然后调用sendRequest 

    8.sendRequest(HttpRequestBase request)

     1 private ResponseInfo<T> sendRequest(HttpRequestBase request) throws HttpException {
     2 
     3 
     4     HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler();
     5     while (true) {
     6 
     7         requestMethod = request.getMethod();
     8         if (HttpUtils.sHttpCache.isEnabled(requestMethod)) {
     9           String result = HttpUtils.sHttpCache.get(requestUrl);
    10           if (result != null) {
    11             return new ResponseInfo<T>(null, (T) result, true);
    12           }
    13         }
    14 
    15 
    16         ResponseInfo<T> responseInfo = null;
    17         if (!isCancelled()) {
    18           HttpResponse response = client.execute(request, context);
    19           responseInfo = handleResponse(response);
    20         }
    21         return responseInfo;
    22       } catch (Exception e) {
    23         exception = e;
    24         retry = retryHandler.retryRequest(exception, ++retriedCount, context);
    25       } 
    26       if (!retry) {
    27         throw new HttpException(exception);
    28       }
    29     }
    30   }

    这个方法仔细看看, 

    先获取下client.getHttpRequestRetryHandler(),获取retry的设置

    1 requestMethod = request.getMethod();
    2                 if (HttpUtils.sHttpCache.isEnabled(requestMethod)) {
    3                     String result = HttpUtils.sHttpCache.get(requestUrl);
    4                     if (result != null) {
    5                         return new ResponseInfo<T>(null, (T) result, true);
    6                     }
    7                 }

    如果使用了缓存则通过requestUrl去httpCache去获取,获取到了则创建ResponseInfo对象 

    如果没有缓存

    1 HttpResponse response = client.execute(request, context);
    2                     responseInfo = handleResponse(response);

    调用httpClient执行http请求,获取到得结果交由handleResponse处理 

    如果之前的处理出现异常则

    1 retry = retryHandler.retryRequest(exception, ++retriedCount, context);

    调用retry机制,直到有结果,或者超过retry的次数 

    9.handleResponse()

    第8步的时候,如果client执行获取到结果则调用handleResponse(HttpResponse response)处理结果

     1 ResponseInfo<T> handleResponse(HttpResponse response) throws HttpException, IOException {
     2 
     3     StatusLine status = response.getStatusLine();
     4     int statusCode = status.getStatusCode();
     5     if (statusCode < 300) {
     6   
     7           result = mStringDownloadHandler.handleEntity(entity, this, charset);
     8           if (HttpUtils.sHttpCache.isEnabled(requestMethod)) {
     9             HttpUtils.sHttpCache.put(requestUrl, (String) result, expiry);
    10           }
    11         
    12       }
    13       return new ResponseInfo<T>(response, (T) result, false);
    14     } else if (statusCode == 301 || statusCode == 302) {
    15       if (httpRedirectHandler == null) {
    16         httpRedirectHandler = new DefaultHttpRedirectHandler();
    17       }
    18       HttpRequestBase request = httpRedirectHandler.getDirectRequest(response);
    19       if (request != null) {
    20         return this.sendRequest(request);
    21       }
    22     } 
    23     return null;
    24   }

    这个方法主要根据返回的statuscode处理,<300将结果存在HttpCache里,301或者302则处理重定向 

    10.publishProgress(UPDATE_SUCCESS, responseInfo)

    在获得ResponseInfo后,调用  publishProgress(UPDATE_SUCCESS, responseInfo)方法,最后会调用onProgressUpdate方法 

     1 protected void onProgressUpdate(Object... values) {
     2       case UPDATE_SUCCESS:
     3         if (values.length != 2) return;
     4         this.state = State.SUCCESS;
     5         callback.onSuccess((ResponseInfo<T>) values[1]);
     6         break;
     7       default:
     8         break;
     9     }
    10   }

    这onProgressUpdate里发现最终调用第2步传进来的callback 

    整个的调用过程基本上是这样。

    1.创建httputils时创建httpClient,调用send发送请求

    2. 调用send时,创建httpHandler,此类继承CompatibleAsyncTask

    3.在httpHandler的doInBackground真正的处理http请求,此时会判断是否有缓存,获取结果后,通过回调处理结果

  • 相关阅读:
    从头梳理一下经常问到的 “零拷贝” 问题!
    Redis缓存使用中的热key问题
    使用Redis,你必须知道的21个注意要点
    一文理解 Redis 的核心原理与技术!
    大厂常问的Redis面试题
    三种不同场景下的 Kubernetes 服务调试方法
    Docker 和 Kubernetes:root 与特权
    DRBD详细解说及配置过程记录
    MySQL 高可用方案-PXC环境部署记录
    MySQL高可用方案
  • 原文地址:https://www.cnblogs.com/vijozsoft/p/5647099.html
Copyright © 2020-2023  润新知