xUtils是github上的一个Android开源工具项目,其中HttpUtils模块是处理网络连接部分,刚好最近想整理下Android网络编程知识,今天学习下xUtils中HttpUtils.
xUtils项目地址:https://github.com/wyouflf/xUtils
先看看分析的时序图,了解下基本的过程
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;
}
}
}
}
});
}
注意这个类ThreadSafeClientConnManager,它主要是为了使用线程安全的连接管理来创建HttpClient。
不过这里就有个疑问了,之前看资料了解到一般创建HttpClient都是用的 单例模式,说是一个httpClient就相当于是一个小型的浏览器,如果创建多个httpClient就很消耗资源了,我看了这个开源项目给的demo,是创建一个请求就创建一个HttpClient, 到时跟作者联系看看是什么回事。
2.发送请求
http.send(HttpRequest.HttpMethod.GET,
"http://www.baidu.com",
new RequestCallBack() {
@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 responseInfo) {
resultText.setText("response:" + responseInfo.result);
}
@Override
public void onFailure(HttpException error, String msg) {
resultText.setText(msg);
}
});
HttpRequest.HttpMethod.GET指明请求的方式,
"http://www.baidu.com"请求的地址,
new RequestCallBack
3. http.send()
public HttpHandler send(HttpRequest.HttpMethod method, String url,
RequestCallBack callBack) {
return send(method, url, null, callBack);
}
public HttpHandler send(HttpRequest.HttpMethod method, String url, RequestParams params,
RequestCallBack callBack) {
if (url == null) throw new IllegalArgumentException("url may not be null");
HttpRequest request = new HttpRequest(method, url);
return sendRequest(request, params, callBack);
}
private HttpHandler sendRequest(HttpRequest request, RequestParams params, RequestCallBack callBack) {
HttpHandler handler = new HttpHandler(httpClient, httpContext, responseTextCharset, callBack);
handler.setExpiry(currentRequestExpiry);
handler.setHttpRedirectHandler(httpRedirectHandler);
request.setRequestParams(params, handler);
handler.executeOnExecutor(executor, request);
return handler;
}
在sendRequest里创建HttpHandler对象
4. HttpHandler
HttpHandler extends CompatibleAsyncTask
参看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 responseInfo = sendRequest(request);
if (responseInfo != null) {
this.publishProgress(UPDATE_SUCCESS, responseInfo);
return null;
}
先处理传递进来的params,调用publishProgress更新下当前的状态,然后调用sendRequest
8.sendRequest(HttpRequestBase request)
private ResponseInfo 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(null, (T) result, true);
}
}
ResponseInfo 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(null, (T) result, true);
}
}
如果使用了缓存则通过requestUrl去httpCache去获取,获取到了则创建ResponseInfo对象
如果没有缓存
HttpResponse response = client.execute(request, context);
responseInfo = handleResponse(response);
如果之前的处理出现异常则
retry = retryHandler.retryRequest(exception, ++retriedCount, context);
9.handleResponse()
第8步的时候,如果client执行获取到结果则调用handleResponse(HttpResponse response)处理结果
ResponseInfo 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(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) values[1]);
break;
default:
break;
}
}
这onProgressUpdate里发现最终调用第2步传进来的callback
整个的调用过程基本上是这样。
1.创建httputils时创建httpClient,调用send发送请求
2. 调用send时,创建httpHandler,此类继承CompatibleAsyncTask
3.在httpHandler的doInBackground真正的处理http请求,此时会判断是否有缓存,获取结果后,通过回调处理结果