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