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. @Override
  6. public void onStart() {
  7. resultText.setText("conn...");
  8. }
  9.  
  10. @Override
  11. public void onLoading(long total, long current, boolean isUploading) {
  12. resultText.setText(current + "/" + total);
  13. }
  14.  
  15. @Override
  16. public void onSuccess(ResponseInfo<String> responseInfo) {
  17. resultText.setText("response:" + responseInfo.result);
  18. }
  19.  
  20. @Override
  21. public void onFailure(HttpException error, String msg) {
  22. resultText.setText(msg);
  23. }
  24. });

调用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. lastUpdateTime = SystemClock.uptimeMillis();
  6.  
  7. ResponseInfo<T> responseInfo = sendRequest(request);
  8. if (responseInfo != null) {
  9. this.publishProgress(UPDATE_SUCCESS, responseInfo);
  10. return null;
  11. }

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

8.sendRequest(HttpRequestBase request)

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

这个方法仔细看看,

先获取下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请求,此时会判断是否有缓存,获取结果后,通过回调处理结果

Android开源项目xUtils HttpUtils模块分析(转)的更多相关文章

  1. [Android] 开源框架 xUtils HttpUtils 代理设置 (Temporary Redirect错误)

    今天简单学习了一下xUtils的使用 https://github.com/wyouflf/xUtils 其中用到HttpUtils模块时,发现总是出现Temporary Redirect 错误. 查 ...

  2. Android 开源项目PhotoView源码分析

    https://github.com/chrisbanes/PhotoView/tree/master/library 这个就是项目地址,相信很多人都用过,我依然不去讲怎么使用.只讲他的原理和具体实现 ...

  3. 2015-2016最火的Android开源项目--github开源项目集锦(不看你就out了)

    标签: Android开发开源项目最火Android项目github 2015-2016最火的Android开源项目 本文整理与集结了近期github上使用最广泛最火热与最流行的开源项目,想要充电与提 ...

  4. Android开源项目分类汇总

    目前包括: Android开源项目第一篇——个性化控件(View)篇   包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView. ...

  5. 59.Android开源项目及库 (转)

    转载 : https://github.com/Tim9Liu9/TimLiu-Android?hmsr=toutiao.io&utm_medium=toutiao.io&utm_so ...

  6. GitHub上史上最全的Android开源项目分类汇总 (转)

    GitHub上史上最全的Android开源项目分类汇总 标签: github android 开源 | 发表时间:2014-11-23 23:00 | 作者:u013149325 分享到: 出处:ht ...

  7. GitHub上史上最全的Android开源项目分类汇总

    今天在看博客的时候,无意中发现了 @Trinea 在GitHub上的一个项目 Android开源项目分类汇总 ,由于类容太多了,我没有一个个完整地看完,但是里面介绍的开源项目都非常有参考价值,包括很炫 ...

  8. Android 开源项目分类汇总(转)

    Android 开源项目分类汇总(转) ## 第一部分 个性化控件(View)主要介绍那些不错个性化的 View,包括 ListView.ActionBar.Menu.ViewPager.Galler ...

  9. 【开源项目8】Android开源项目分类汇总【畜生级别】

    欢迎大家推荐好的Android开源项目,可直接Commit或在 收集&提交页 中告诉我,欢迎Star.Fork :) 微博:Trinea    主页:www.trinea.cn    邮箱:t ...

随机推荐

  1. zstu4273 玩具 2017-03-22 14:18 49人阅读 评论(0) 收藏

    4273: 玩具 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 700  Solved: 129 Description 商店有n个玩具,第i个玩具有 ...

  2. CYUSB3014固件部分低版本工程在Eclipse中编译得到img文件时无效的解决方案

    最近在做基于我们AC6102开发板的UVC图像视频方案,下载了官方的an75779应用工程,但是倒入到FX3—SDK自带的Eclipse中后,却无法编译生成img文件,经过比对后确认是生成该文件的命令 ...

  3. How do I determine if I'm being run under the debugger?

    #include <assert.h>#include <stdbool.h>#include <sys/types.h>#include <unistd.h ...

  4. Android-SQLiteOpenHelper里增删改查

    为什么要写一篇,Android-SQLiteOpenHelper里增删改查,的文章呢: 因为之前的方式是:MySQLiteOpenHelper(只负责 生成打开据库/生成打开表/升级表),在其他端:完 ...

  5. ASP.NET Core2读写InfluxDB时序数据库

    在我们很多应用中会遇到有一种基于一系列时间的数据需要处理,通过时间的顺序可以将这些数据点连成线,再通过数据统计后可以做成多纬度的报表,也可通过机器学习来实现数据的预测告警.而时序数据库就是用于存放管理 ...

  6. Git Note - git tag

    git tag is used to create labels, usually for version numbers. Format: git tag <TagName> <r ...

  7. C#基础之流程控制语句详解

    C#程序的执行都是一行接一行.自上而下地进行,不遗漏任何代码.为了让程序能按照开发者所设计的流程进行执行,必然需要进行条件判断.循环和跳转等过程,这就需要实现流程控制.C#中的流程控制包含了条件语句. ...

  8. Java多线程编程:Callable、Future和FutureTask浅析(多线程编程之四)

    java多线程-概念&创建启动&中断&守护线程&优先级&线程状态(多线程编程之一)java多线程同步以及线程间通信详解&消费者生产者模式&死锁& ...

  9. iOS 设置 (plist)

    Architectures:

  10. Codeforces Beta Round #75 (Div. 1 Only) B. Queue 二分

    B. Queue Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 codeforces.com/problemset/problem/91/B Descrip ...