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

时间:2023-02-16 21:03:20

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

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

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

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

1. Activity创建HttpUtils对象

 HttpUtils http = new HttpUtils();

查看HttpUtils类的构造函数

 public HttpUtils() {
this(HttpUtils.DEFAULT_CONN_TIMEOUT);
} public HttpUtils(int connTimeout) {
HttpParams params = new BasicHttpParams(); ConnManagerParams.setTimeout(params, connTimeout);
HttpConnectionParams.setSoTimeout(params, connTimeout);
HttpConnectionParams.setConnectionTimeout(params, connTimeout); ConnManagerParams.setMaxConnectionsPerRoute(params, new ConnPerRouteBean(10));
ConnManagerParams.setMaxTotalConnections(params, 10); HttpConnectionParams.setTcpNoDelay(params, true);
HttpConnectionParams.setSocketBufferSize(params, 1024 * 8);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", DefaultSSLSocketFactory.getSocketFactory(), 443)); httpClient = new DefaultHttpClient(new ThreadSafeClientConnManager(params, schemeRegistry), params); httpClient.setHttpRequestRetryHandler(new RetryHandler(DEFAULT_RETRY_TIMES)); httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
@Override
public void process(org.apache.http.HttpRequest httpRequest, HttpContext httpContext) throws org.apache.http.HttpException, IOException {
if (!httpRequest.containsHeader(HEADER_ACCEPT_ENCODING)) {
httpRequest.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
}
}
}); httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
@Override
public void process(HttpResponse response, HttpContext httpContext) throws org.apache.http.HttpException, IOException {
final HttpEntity entity = response.getEntity();
if (entity == null) {
return;
}
final Header encoding = entity.getContentEncoding();
if (encoding != null) {
for (HeaderElement element : encoding.getElements()) {
if (element.getName().equalsIgnoreCase("gzip")) {
response.setEntity(new GZipDecompressingEntity(response.getEntity()));
return;
}
}
}
}
});
}

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

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

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

2.发送请求

  http.send(HttpRequest.HttpMethod.GET,
"http://www.baidu.com",
new RequestCallBack<String>() { @Override
public void onStart() {
resultText.setText("conn...");
} @Override
public void onLoading(long total, long current, boolean isUploading) {
resultText.setText(current + "/" + total);
} @Override
public void onSuccess(ResponseInfo<String> responseInfo) {
resultText.setText("response:" + responseInfo.result);
} @Override
public void onFailure(HttpException error, String msg) {
resultText.setText(msg);
}
});

调用send方法发生请求,

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

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

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

3. http.send()

 public <T> HttpHandler<T> send(HttpRequest.HttpMethod method, String url,
RequestCallBack<T> callBack) {
return send(method, url, null, callBack);
} public <T> HttpHandler<T> send(HttpRequest.HttpMethod method, String url, RequestParams params,
RequestCallBack<T> callBack) {
if (url == null) throw new IllegalArgumentException("url may not be null"); HttpRequest request = new HttpRequest(method, url);
return sendRequest(request, params, callBack);
}
private <T> HttpHandler<T> sendRequest(HttpRequest request, RequestParams params, RequestCallBack<T> callBack) { HttpHandler<T> handler = new HttpHandler<T>(httpClient, httpContext, responseTextCharset, callBack); handler.setExpiry(currentRequestExpiry);
handler.setHttpRedirectHandler(httpRedirectHandler);
request.setRequestParams(params, handler); handler.executeOnExecutor(executor, request);
return handler;
}

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

在sendRequest里创建HttpHandler对象

4. HttpHandler

 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)

 //先处理传递进来的params

   this.publishProgress(UPDATE_START);

   lastUpdateTime = SystemClock.uptimeMillis();

   ResponseInfo<T> responseInfo = sendRequest(request);
if (responseInfo != null) {
this.publishProgress(UPDATE_SUCCESS, responseInfo);
return null;
}

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

8.sendRequest(HttpRequestBase request)

 private ResponseInfo<T> sendRequest(HttpRequestBase request) throws HttpException {

     HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler();
while (true) { requestMethod = request.getMethod();
if (HttpUtils.sHttpCache.isEnabled(requestMethod)) {
String result = HttpUtils.sHttpCache.get(requestUrl);
if (result != null) {
return new ResponseInfo<T>(null, (T) result, true);
}
} ResponseInfo<T> responseInfo = null;
if (!isCancelled()) {
HttpResponse response = client.execute(request, context);
responseInfo = handleResponse(response);
}
return responseInfo;
} catch (Exception e) {
exception = e;
retry = retryHandler.retryRequest(exception, ++retriedCount, context);
}
if (!retry) {
throw new HttpException(exception);
}
}
}

这个方法仔细看看,

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

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

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

如果没有缓存

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

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

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

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

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

9.handleResponse()

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

 ResponseInfo<T> handleResponse(HttpResponse response) throws HttpException, IOException {

     StatusLine status = response.getStatusLine();
int statusCode = status.getStatusCode();
if (statusCode < 300) { result = mStringDownloadHandler.handleEntity(entity, this, charset);
if (HttpUtils.sHttpCache.isEnabled(requestMethod)) {
HttpUtils.sHttpCache.put(requestUrl, (String) result, expiry);
} }
return new ResponseInfo<T>(response, (T) result, false);
} else if (statusCode == 301 || statusCode == 302) {
if (httpRedirectHandler == null) {
httpRedirectHandler = new DefaultHttpRedirectHandler();
}
HttpRequestBase request = httpRedirectHandler.getDirectRequest(response);
if (request != null) {
return this.sendRequest(request);
}
}
return null;
}

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

10.publishProgress(UPDATE_SUCCESS, responseInfo)

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

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

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

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

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

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

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

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

  1. &lbrack;Android&rsqb; 开源框架 xUtils HttpUtils 代理设置 &lpar;Temporary Redirect错误&rpar;

    今天简单学习了一下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开源项目集锦&lpar;不看你就out了&rpar;

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

  4. Android开源项目分类汇总

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

  5. 59&period;Android开源项目及库 &lpar;转&rpar;

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

  6. GitHub上史上最全的Android开源项目分类汇总 &lpar;转&rpar;

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

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

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

  8. Android 开源项目分类汇总&lpar;转&rpar;

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

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

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

随机推荐

  1. C&num;、不说再见

    公司技术转型,.NET To Java,以后逐渐踏入Java阵营. 再见了 Java嫌弃的老同学,再见了 来不及说出的谢谢 再见了 不会再有的.NET,再见了 我留给你毕业册的最后一页 我相信 我们还 ...

  2. C&num;中的new修饰符

    MSDN:在用作声明修饰符时,new 关键字可以显式隐藏从基类继承的成员. 隐藏继承的成员时,该成员的派生版本将替换基类版本. 虽然可以不使用 new 修饰符来隐藏成员,但将收到编译器警告. 如果使用 ...

  3. 在 C&num; 中加载自己编写的动态链接库

    一.发生的背景    在开发新项目中使用了新的语言开发 C# 和新的技术方案 WEB Service,但是在新项目中,一些旧的模块需要继续使用,一般是采用 C 或 C++ 或 Delphi 编写的,如 ...

  4. 启发式搜索 A&ast;算法的OC 实现

    前两天重新学习了下A*算法,上次学习A*算法已经是5年前了,看到网上铺天盖地的A*算法都是C.C++等等其他语言的,就是没有OC 的,所以抽空写了一份.今天太晚了就不说明A*算法的细节了,大家如果想学 ...

  5. 零售ERP开发(一)

    随着企业信息化不断提高,各种企业管理系统应用而生:怎么才能开发一套简洁.易用.功能健全的管理系统,尤其是能够帮助企业做出重大策略的系统,一致是我们追求的目标.近些年,接触的Erp系统主要包括国内比较知 ...

  6. Mercurial简介

    前言     目前所在的公司的版本控制使用的是Mercurial,它也有一个对应的客户端小乌龟,但是Mercurial跟我们之前使用的SVN有着本质的区别,对于其区别会在下一篇中介绍到,这次主要是带领 ...

  7. bzoj 2753&colon; &lbrack;SCOI2012&rsqb;滑雪与时间胶囊

    Description a180285非常喜欢滑雪.他来到一座雪山,这里分布着M条供滑行的轨道和N个轨道之间的交点(同时也是景点),而且每个景点都有一编号i(1<=i<=N)和一高度Hi. ...

  8. &lbrack;LeetCode&rsqb; Complex Number Multiplication 复数相乘

    Given two strings representing two complex numbers. You need to return a string representing their m ...

  9. mysql创建唯一索引,避免数据重复插入

    多台服务器使用一个数据库时,有时就会出现重复插入的情况,eg:people表中的姓名和身份证号 此时可以给姓名和身份证号创建唯一索引, 创建语句:alter table people add uniq ...

  10. 洛谷P1342 请柬(SPFA)

    To 洛谷.1342 请柬 题目描述 在电视时代,没有多少人观看戏剧表演.Malidinesia古董喜剧演员意识到这一事实,他们想宣传剧院,尤其是古色古香的喜剧片.他们已经打印请帖和所有必要的信息和计 ...