在Android开发中,发送、处理http请求简直太常见了,以致于咱们的代码里处处充斥着各类HttpClient和与之相关又臭又长的代码,html
它们存在于你代码的各个角落,每次看见都使人做呕,而你仅仅是为了server能返回一个string或者json给你。每次当我本身写这样java
的代码时,我都会想能不能简化下这个流程,可能二、3行代码就能搞定。由于针对最简单的case,我只须要提供request url,成功时的android
callback和(或)失败时的callback,仅此而已。针对这一类问题(需求),能够说android-async-http提供了几乎完美的解决方案。git
经过使用它能够大大简化你的代码,不只如此,你的代码看上去也优雅多了。github
当我第一眼看到它时就被吸引住了,特别是async关键字,干咱们这行的都知道,这是异步执行,也就是说它的网络请求自动在非UIajax
线程里执行,你不须要任何额外的操做(好比手动new一个Thread之类)。项目的官方网站:apache
http://loopj.com/android-async-http/,对应的github地址:https://github.com/loopj/android-async-httpjson
我这里简要介绍下:它是专门针对Android在Apache的HttpClient基础上构建的异步的callback-based http client。全部的请求api
全在UI线程以外发生,而callback发生在建立它的线程中,应用了Android的Handler发送消息机制。你也能够把AsyncHttpClient应用在数组
Service中或者后台线程中,库代码会自动识别出它所运行的context。它的feature包括:
1. 发送异步http请求,在匿名callback对象中处理response;
2. http请求发生在UI线程以外;
3. 内部采用线程池来处理并发请求;
4. GET/POST 参数构造,经过RequestParams类。
5. 内置多部分文件上传,不须要第三方库支持;
6. 流式Json上传,不须要额外的库;
7. 能处理环行和相对重定向;
8. 和你的app大小相比来讲,库的size很小,全部的一切只有90kb;
9. 自动智能的请求重试机制在各类各样的移动链接环境中;
10. 自动的gzip响应解码;
11. 内置多种形式的响应解析,有原生的字节流,string,json对象,甚至能够将response写到文件中;
12. 永久的cookie保存,内部实现用的是Android的SharedPreferences;
13. 经过BaseJsonHttpResponseHandler和
各类json库集成;
14. 支持SAX解析器;
15. 支持各类语言和content编码,不只仅是UTF-8。
大概翻译了下,这些只是大致的概览,具体的细节还得在使用过程当中慢慢感觉、学习。
接下来,带领你们看看应用android-async-http来写代码是个啥样子。简单来讲你只须要3步,
1. 建立一个AsyncHttpClient;
2. (可选的)经过RequestParams对象设置请求参数;
3. 调用AsyncHttpClient的某个get方法,传递你须要的(成功和失败时)callback接口实现,通常都是匿名内部类
,实现了AsyncHttpResponseHandler,类库本身也提供了好些现成的response handler,你通常不须要本身建立一个。
来看看代码如何写:
AsyncHttpClient client = new AsyncHttpClient(); client.get("http://www.google.com", new AsyncHttpResponseHandler() { @Override public void onStart() { // called before request is started } @Override public void onSuccess(int statusCode, Header[] headers, byte[] response) { // called when response HTTP status is "200 OK" } @Override public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) { // called when response HTTP status is "4XX" (eg. 401, 403, 404) } @Override public void onRetry(int retryNo) { // called when request is retried } });
是否是很简洁,有没有被震撼到?反正我本身第一次看到的时候有种相见恨晚的感受,这简直就是我日思夜想的方式啊!这里你只须要经过
匿名内部类的方式实现AsyncHttpResponseHandler,并且更棒的是你只须要override感兴趣的方法,好比通常都是onSuccess和onFailure。
这个版本的get方法没有为请求传递任何参数,固然你也能够经过RequestParams来传递各类参数,以下:
AsyncHttpClient client = new AsyncHttpClient(); RequestParams params = new RequestParams(); params.put("key", "value"); params.put("more", "data"); client.get("http://www.google.com", params, new AsyncHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, byte[] response) { System.out.println(response); } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { Log.d("ERROR", error); } } );
以上的例子是返回的response直接是原生字节流的状况,若是你须要把返回的结果当一个String对待,这时只须要匿名实现一个
TextHttpResponseHandler就行,其继承自AsyncHttpResponse,并将原生的字节流根据指定的encoding转化成了string对象,
代码以下:
AsyncHttpClient client = new AsyncHttpClient(); RequestParams params = new RequestParams(); params.put("key", "value"); params.put("more", "data"); client.get("http://www.google.com", params, new TextHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, String response) { System.out.println(response); } @Override public void onFailure(int statusCode, Header[] headers, String responseBody, Throwable error) { Log.d("ERROR", error); } } );
一样的方式,你能够发送json请求,代码以下:
String url = "https://ajax.googleapis.com/ajax/services/search/images"; AsyncHttpClient client = new AsyncHttpClient(); RequestParams params = new RequestParams(); params.put("q", "android"); params.put("rsz", "8"); client.get(url, params, new JsonHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, JSONObject response) { // Handle resulting parsed JSON response here } @Override public void onSuccess(int statusCode, Header[] headers, JSONArray response) { // Handle resulting parsed JSON response here } });
看到了没,返回的response已经自动转化成JSONObject了,固然也支持JSONArray类型,override你须要的那个版本就行。
有了AsyncHttpClient,要实现这些功能是否是很简单呢?固然这里只是很初级的介绍和使用,剩下的还须要开发者本身参考官方
文档、源码(官方甚至提供了一个Sample使用的集合),在实际项目中实践。最后,强烈建议你们使用,是时候和冗长乏味的代码说
我大概浏览了下其代码,关键部分能够分为这4个模块:
1. AsyncHttpClient本身一个模块;
2. AsyncHttpRequest和RequestHandler一个模块;
3. AsyncHttpResponseHandler及其各类特定子类一个模块;
4. RetryHandler,自动重试机制。
咱们能够很清楚的看出门道来,大致是按照client、request、response,这样的方式组织的。接下来咱们的代码分析也就按照这个顺序进行。
先来讲AsyncHttpClient,来看其关键字段和ctor,代码以下:
public static final String LOG_TAG = "AsyncHttpClient"; public static final String HEADER_CONTENT_TYPE = "Content-Type"; public static final String HEADER_CONTENT_RANGE = "Content-Range"; public static final String HEADER_CONTENT_ENCODING = "Content-Encoding"; public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition"; public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding"; public static final String ENCODING_GZIP = "gzip"; public static final int DEFAULT_MAX_CONNECTIONS = 10; public static final int DEFAULT_SOCKET_TIMEOUT = 10 * 1000; public static final int DEFAULT_MAX_RETRIES = 5; public static final int DEFAULT_RETRY_SLEEP_TIME_MILLIS = 1500; public static final int DEFAULT_SOCKET_BUFFER_SIZE = 8192; private int maxConnections = DEFAULT_MAX_CONNECTIONS; private int connectTimeout = DEFAULT_SOCKET_TIMEOUT; private int responseTimeout = DEFAULT_SOCKET_TIMEOUT; // 各类参数设置 private final DefaultHttpClient httpClient; // 包装的Apache DefaultHttpClient private final HttpContext httpContext; private ExecutorService threadPool; // 执行网络请求的线程池 private final Map<Context, List<RequestHandle>> requestMap; // 与Android Context对应的请求map private final Map<String, String> clientHeaderMap; // 客户端的请求header map private boolean isUrlEncodingEnabled = true; // 容许url encoding
接下来看看各类ctor,以下:
/** * Creates a new AsyncHttpClient with default constructor arguments values */ public AsyncHttpClient() { // 通常客户端代码中都直接调用这个版本的ctor this(false, 80, 443); } /** * Creates a new AsyncHttpClient. * * @param httpPort non-standard HTTP-only port */ public AsyncHttpClient(int httpPort) { this(false, httpPort, 443); } /** * Creates a new AsyncHttpClient. * * @param httpPort non-standard HTTP-only port * @param httpsPort non-standard HTTPS-only port */ public AsyncHttpClient(int httpPort, int httpsPort) { this(false, httpPort, httpsPort); } /** * Creates new AsyncHttpClient using given params * * @param fixNoHttpResponseException Whether to fix or not issue, by omitting SSL verification * @param httpPort HTTP port to be used, must be greater than 0 * @param httpsPort HTTPS port to be used, must be greater than 0 */ public AsyncHttpClient(boolean fixNoHttpResponseException, int httpPort, int httpsPort) { this(getDefaultSchemeRegistry(fixNoHttpResponseException, httpPort, httpsPort)); } /** * Returns default instance of SchemeRegistry * * @param fixNoHttpResponseException Whether to fix or not issue, by omitting SSL verification * @param httpPort HTTP port to be used, must be greater than 0 * @param httpsPort HTTPS port to be used, must be greater than 0 */ private static SchemeRegistry getDefaultSchemeRegistry(boolean fixNoHttpResponseException, int httpPort, int httpsPort) { if (fixNoHttpResponseException) { // 若是你请求的url是https的,而且遇到了SSL验证之类的错误,那么你应该将此值设为true试试 Log.d(LOG_TAG, "Beware! Using the fix is insecure, as it doesn't verify SSL certificates."); } if (httpPort < 1) { httpPort = 80; Log.d(LOG_TAG, "Invalid HTTP port number specified, defaulting to 80"); } if (httpsPort < 1) { httpsPort = 443; Log.d(LOG_TAG, "Invalid HTTPS port number specified, defaulting to 443"); } // Fix to SSL flaw in API < ICS // See https://code.google.com/p/android/issues/detail?id=13117 SSLSocketFactory sslSocketFactory; if (fixNoHttpResponseException) { // 感兴趣的同窗可自行看看MySSLSocketFactory的实现,基本上是省略了SSL验证环节 sslSocketFactory = MySSLSocketFactory.getFixedSocketFactory(); } else { sslSocketFactory = SSLSocketFactory.getSocketFactory(); } SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), httpPort)); schemeRegistry.register(new Scheme("https", sslSocketFactory, httpsPort)); return schemeRegistry; } /** * Creates a new AsyncHttpClient. * * @param schemeRegistry SchemeRegistry to be used */ public AsyncHttpClient(SchemeRegistry schemeRegistry) { // 最终调到的是这个版本。。。 BasicHttpParams httpParams = new BasicHttpParams(); // 接下来是设置各类参数。。。 ConnManagerParams.setTimeout(httpParams, connectTimeout); ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(maxConnections)); ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS); HttpConnectionParams.setSoTimeout(httpParams, responseTimeout); HttpConnectionParams.setConnectionTimeout(httpParams, connectTimeout); HttpConnectionParams.setTcpNoDelay(httpParams, true); HttpConnectionParams.setSocketBufferSize(httpParams, DEFAULT_SOCKET_BUFFER_SIZE); HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1); ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(httpParams, schemeRegistry); // 初始化关键字段 threadPool = getDefaultThreadPool(); requestMap = Collections.synchronizedMap(new WeakHashMap<Context, List<RequestHandle>>()); clientHeaderMap = new HashMap<String, String>(); httpContext = new SyncBasicHttpContext(new BasicHttpContext()); httpClient = new DefaultHttpClient(cm, httpParams); httpClient.addRequestInterceptor(new HttpRequestInterceptor() { @Override public void process(HttpRequest request, HttpContext context) { if (!request.containsHeader(HEADER_ACCEPT_ENCODING)) { request.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP); } for (String header : clientHeaderMap.keySet()) { if (request.containsHeader(header)) { Header overwritten = request.getFirstHeader(header); Log.d(LOG_TAG, String.format("Headers were overwritten! (%s | %s) overwrites (%s | %s)", header, clientHeaderMap.get(header), overwritten.getName(), overwritten.getValue()) ); //remove the overwritten header request.removeHeader(overwritten); } request.addHeader(header, clientHeaderMap.get(header)); } } }); httpClient.addResponseInterceptor(new HttpResponseInterceptor() { @Override public void process(HttpResponse response, HttpContext context) { 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(ENCODING_GZIP)) { response.setEntity(new InflatingEntity(entity)); break; } } } } }); httpClient.addRequestInterceptor(new HttpRequestInterceptor() { @Override public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE); CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute( ClientContext.CREDS_PROVIDER); HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST); if (authState.getAuthScheme() == null) { AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort()); Credentials creds = credsProvider.getCredentials(authScope); if (creds != null) { authState.setAuthScheme(new BasicScheme()); authState.setCredentials(creds); } } } }, 0); // 设置重试Handler,会在合适的状况下自动重试 httpClient.setHttpRequestRetryHandler(new RetryHandler(DEFAULT_MAX_RETRIES, DEFAULT_RETRY_SLEEP_TIME_MILLIS)); }
接下来重要的就是各类HTTP head、get、post、delete方法,它们最终调用的都是sendRequest方法,以下:
/** * Puts a new request in queue as a new thread in pool to be executed * * @param client HttpClient to be used for request, can differ in single requests * @param contentType MIME body type, for POST and PUT requests, may be null * @param context Context of Android application, to hold the reference of request * @param httpContext HttpContext in which the request will be executed * @param responseHandler ResponseHandler or its subclass to put the response into * @param uriRequest instance of HttpUriRequest, which means it must be of HttpDelete, * HttpPost, HttpGet, HttpPut, etc. * @return RequestHandle of future request process */ protected RequestHandle sendRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType, ResponseHandlerInterface responseHandler, Context context) { if (uriRequest == null) { throw new IllegalArgumentException("HttpUriRequest must not be null"); } if (responseHandler == null) { throw new IllegalArgumentException("ResponseHandler must not be null"); } if (responseHandler.getUseSynchronousMode()) { throw new IllegalArgumentException("Synchronous ResponseHandler used in AsyncHttpClient. You should create your response handler in a looper thread or use SyncHttpClient instead."); } if (contentType != null) { uriRequest.setHeader(HEADER_CONTENT_TYPE, contentType); } responseHandler.setRequestHeaders(uriRequest.getAllHeaders()); responseHandler.setRequestURI(uriRequest.getURI()); // 下面的这3行是重点,建立请求,提交请求到线程池,将请求包装到RequestHandle用于以后的取消、管理 AsyncHttpRequest request = newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context); threadPool.submit(request); // 能submit说明request至少是个Runnable RequestHandle requestHandle = new RequestHandle(request); if (context != null) { // 若是Android context非空的话,作一些关联操做,后面能够经过context来取消request的执行 // Add request to request map List<RequestHandle> requestList = requestMap.get(context); synchronized (requestMap) { if (requestList == null) { requestList = Collections.synchronizedList(new LinkedList<RequestHandle>()); requestMap.put(context, requestList); } } if (responseHandler instanceof RangeFileAsyncHttpResponseHandler) ((RangeFileAsyncHttpResponseHandler) responseHandler).updateRequestHeaders(uriRequest); requestList.add(requestHandle); Iterator<RequestHandle> iterator = requestList.iterator(); while (iterator.hasNext()) { if (iterator.next().shouldBeGarbageCollected()) { iterator.remove(); // 清理已经完成/取消了的请求 } } } return requestHandle; }
看到了吧,发送请求的过程其实重点是建立请求,而后submit到线程池,剩下的事情就交给线程池本身处理了,咱们只须要坐等被调用。
来看看建立请求的方法,代码以下:
/** * Instantiate a new asynchronous HTTP request for the passed parameters. * * @param client HttpClient to be used for request, can differ in single requests * @param contentType MIME body type, for POST and PUT requests, may be null * @param context Context of Android application, to hold the reference of request * @param httpContext HttpContext in which the request will be executed * @param responseHandler ResponseHandler or its subclass to put the response into * @param uriRequest instance of HttpUriRequest, which means it must be of HttpDelete, * HttpPost, HttpGet, HttpPut, etc. * @return AsyncHttpRequest ready to be dispatched */ protected AsyncHttpRequest newAsyncHttpRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType, ResponseHandlerInterface responseHandler, Context context) { return new AsyncHttpRequest(client, httpContext, uriRequest, responseHandler); }
紧接着咱们看看AsyncHttpRequest的实现:
/** * Internal class, representing the HttpRequest, done in asynchronous manner */ public class AsyncHttpRequest implements Runnable { // 这就是submit到线程池的Runnable private final AbstractHttpClient client; private final HttpContext context; private final HttpUriRequest request; private final ResponseHandlerInterface responseHandler; private int executionCount; private boolean isCancelled; private boolean cancelIsNotified; private boolean isFinished; private boolean isRequestPreProcessed; public AsyncHttpRequest(AbstractHttpClient client, HttpContext context, HttpUriRequest request, ResponseHandlerInterface responseHandler) { this.client = client; this.context = context; this.request = request; this.responseHandler = responseHandler; } /** * This method is called once by the system when the request is about to be * processed by the system. The library makes sure that a single request * is pre-processed only once. * * Please note: pre-processing does NOT run on the main thread, and thus * any UI activities that you must perform should be properly dispatched to * the app's UI thread. * * @param request The request to pre-process */ public void onPreProcessRequest(AsyncHttpRequest request) { // default action is to do nothing... } /** * This method is called once by the system when the request has been fully * sent, handled and finished. The library makes sure that a single request * is post-processed only once. * * Please note: post-processing does NOT run on the main thread, and thus * any UI activities that you must perform should be properly dispatched to * the app's UI thread. * * @param request The request to post-process */ public void onPostProcessRequest(AsyncHttpRequest request) { // default action is to do nothing... } @Override public void run() { // 这是在线程池中执行的方法,咱们重点看看 if (isCancelled()) { // 检测,若是已经取消了则直接返回,下面的代码有好屡次作这个检测,由于你永远不知道何时会被取消 return; // 同时也说明了咱们的Request是支持取消的 } // Carry out pre-processing for this request only once. if (!isRequestPreProcessed) { isRequestPreProcessed = true; onPreProcessRequest(this); // callback接口,在一次请求中只调用一次 } if (isCancelled()) { // 再次检查 return; } if (responseHandler != null) { responseHandler.sendStartMessage(); // 发送开始请求消息 } if (isCancelled()) { // 检查 return; } try { makeRequestWithRetries(); // 带自动retry机制的请求 } catch (IOException e) { if (!isCancelled() && responseHandler != null) { responseHandler.sendFailureMessage(0, null, null, e); // 在没取消的状况下,发送失败消息 } else { Log.e("AsyncHttpRequest", "makeRequestWithRetries returned error, but handler is null", e); } } if (isCancelled()) { // 检查again return; } if (responseHandler != null) { // 没取消的状况下,发送完成消息 responseHandler.sendFinishMessage(); } if (isCancelled()) { return; } // Carry out post-processing for this request. onPostProcessRequest(this); // 处理了请求以后的callback isFinished = true; // 设置为true表示这个请求执行完毕了 } private void makeRequest() throws IOException { // 发送一次请求 if (isCancelled()) { return; } // Fixes #115 if (request.getURI().getScheme() == null) { // subclass of IOException so processed in the caller throw new MalformedURLException("No valid URI scheme was provided"); } // 执行请求得到response HttpResponse response = client.execute(request, context); if (isCancelled() || responseHandler == null) { return; } // Carry out pre-processing for this response. responseHandler.onPreProcessResponse(responseHandler, response); // 处理response前 if (isCancelled()) { return; } // The response is ready, handle it. responseHandler.sendResponseMessage(response); // 发送得到的response if (isCancelled()) { return; } // Carry out post-processing for this response. responseHandler.onPostProcessResponse(responseHandler, response); // 处理response后 } private void makeRequestWithRetries() throws IOException { boolean retry = true; IOException cause = null; HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler(); try { while (retry) { // 注意这个循环,当retry为false的时候退出 try { makeRequest(); return; // 请求成功的话,直接返回 } catch (UnknownHostException e) { // switching between WI-FI and mobile data networks can cause a retry which then results in an UnknownHostException // while the WI-FI is initialising. The retry logic will be invoked here, if this is NOT the first retry // (to assist in genuine cases of unknown host) which seems better than outright failure cause = new IOException("UnknownHostException exception: " + e.getMessage()); retry = (executionCount > 0) && retryHandler.retryRequest(cause, ++executionCount, context); } catch (NullPointerException e) { // there's a bug in HttpClient 4.0.x that on some occasions causes // DefaultRequestExecutor to throw an NPE, see // http://code.google.com/p/android/issues/detail?id=5255 cause = new IOException("NPE in HttpClient: " + e.getMessage()); retry = retryHandler.retryRequest(cause, ++executionCount, context); } catch (IOException e) { if (isCancelled()) { // Eating exception, as the request was cancelled return; } cause = e; retry = retryHandler.retryRequest(cause, ++executionCount, context); }
// 各类异常的状况下,计算retry,看仍是否须要retry if (retry && (responseHandler != null)) { // 须要retry的时候,发送retry消息并附带第几回retry了 responseHandler.sendRetryMessage(executionCount); } } } catch (Exception e) { // catch anything else to ensure failure message is propagated Log.e("AsyncHttpRequest", "Unhandled exception origin cause", e);
// 其余的全部不在上述catch里的异常都在这里统一包装成IOException,在最后抛出 cause = new IOException("Unhandled exception: " + e.getMessage()); } // cleaned up to throw IOException throw (cause); // 抛出,以便上层代码知道发生了什么 } public boolean isCancelled() { if (isCancelled) { sendCancelNotification(); } return isCancelled; } private synchronized void sendCancelNotification() { if (!isFinished && isCancelled && !cancelIsNotified) { cancelIsNotified = true; if (responseHandler != null) responseHandler.sendCancelMessage(); } } public boolean isDone() { return isCancelled() || isFinished; } public boolean cancel(boolean mayInterruptIfRunning) { isCancelled = true; request.abort(); return isCancelled(); } }
紧接着,咱们大概提下RequestHandle,它只是一个持有AsyncHttpRequest对象的弱引用,其方法内部都delegate给了AsyncHttpRequest,
很是简单,感兴趣的同窗可自行阅读。
看完了Request,接下来该看看各类Response了,他们都实现了ResponseHandlerInterface接口,这里咱们重点看下AsyncHttpResponseHandler,
由于它是后面全部更具体的子类的基础,其ctor代码以下:
/** * Creates a new AsyncHttpResponseHandler */ public AsyncHttpResponseHandler() { // 不指定looper this(null); } /** * Creates a new AsyncHttpResponseHandler with a user-supplied looper. If * the passed looper is null, the looper attached to the current thread will * be used. * * @param looper The looper to work with */ public AsyncHttpResponseHandler(Looper looper) { // 若是没指定looper的话,会用当前线程的looper顶替 this.looper = looper == null ? Looper.myLooper() : looper; // Use asynchronous mode by default. setUseSynchronousMode(false); // 默认是异步的方式,这里异步的意思是指对response的处理发生在与looper } // 关联的线程中,而不是请求发生的线程池里的线程中 @Override public void setUseSynchronousMode(boolean sync) { // A looper must be prepared before setting asynchronous mode. if (!sync && this.looper == null) { sync = true; // 一种错误的状况,强制使用同步mode Log.w(LOG_TAG, "Current thread has not called Looper.prepare(). Forcing synchronous mode."); } // If using asynchronous mode. if (!sync && handler == null) { // 初始化handler // Create a handler on current thread to submit tasks handler = new ResponderHandler(this, this.looper); } else if (sync && handler != null) { // TODO: Consider adding a flag to remove all queued messages. handler = null; } useSynchronousMode = sync; }
通常来讲,咱们会直接在UI线程中调用无参版本的ctor,也就是说response是和UI线程关联的,全部对其的处理handleMessage是发生
在UI线程中的。若是你想用response的结果来更新UI则这是正确的方式。
接着咱们看看和处理response相关的代码:
/** * Avoid leaks by using a non-anonymous handler class. */ private static class ResponderHandler extends Handler { private final AsyncHttpResponseHandler mResponder; ResponderHandler(AsyncHttpResponseHandler mResponder, Looper looper) { super(looper); this.mResponder = mResponder; } @Override public void handleMessage(Message msg) { // 一个简单的Handler,其handleMessage delegate给了mResponder mResponder.handleMessage(msg); } } // Methods which emulate android's Handler and Message methods protected void handleMessage(Message message) { // 对各类message的处理,回调各类onXXX方法 Object[] response; switch (message.what) { case SUCCESS_MESSAGE: response = (Object[]) message.obj; if (response != null && response.length >= 3) { onSuccess((Integer) response[0], (Header[]) response[1], (byte[]) response[2]); } else { Log.e(LOG_TAG, "SUCCESS_MESSAGE didn't got enough params"); } break; case FAILURE_MESSAGE: response = (Object[]) message.obj; if (response != null && response.length >= 4) { onFailure((Integer) response[0], (Header[]) response[1], (byte[]) response[2], (Throwable) response[3]); } else { Log.e(LOG_TAG, "FAILURE_MESSAGE didn't got enough params"); } break; case START_MESSAGE: onStart(); break; case FINISH_MESSAGE: onFinish(); break; case PROGRESS_MESSAGE: response = (Object[]) message.obj; if (response != null && response.length >= 2) { try { onProgress((Integer) response[0], (Integer) response[1]); } catch (Throwable t) { Log.e(LOG_TAG, "custom onProgress contains an error", t); } } else { Log.e(LOG_TAG, "PROGRESS_MESSAGE didn't got enough params"); } break; case RETRY_MESSAGE: response = (Object[]) message.obj; if (response != null && response.length == 1) { onRetry((Integer) response[0]); } else { Log.e(LOG_TAG, "RETRY_MESSAGE didn't get enough params"); } break; case CANCEL_MESSAGE: onCancel(); break; } } protected void sendMessage(Message msg) { if (getUseSynchronousMode() || handler == null) { handleMessage(msg); // 若是是同步的方式,则handleMessage发生在调用sendMessage的线程中 } else if (!Thread.currentThread().isInterrupted()) { // do not send messages if request has been cancelled handler.sendMessage(msg); // 不然发生在与handler关联的线程中,通常多为UI线程 } }
代码中各类sendXXXMessage都会调用这里的sendMessage方法,只是构造的msg的what、obj不一样而已。而sendXXXMessage方法
会在request的不一样阶段自动被调用,详见AsyncHttpRequest中。下一步咱们看眼对response的解析过程,代码以下:
@Override public void sendResponseMessage(HttpResponse response) throws IOException { // do not process if request has been cancelled if (!Thread.currentThread().isInterrupted()) { StatusLine status = response.getStatusLine(); byte[] responseBody; responseBody = getResponseData(response.getEntity()); // 将response解析成字节数组 // additional cancellation check as getResponseData() can take non-zero time to process if (!Thread.currentThread().isInterrupted()) { if (status.getStatusCode() >= 300) { // 标志失败的状况 sendFailureMessage(status.getStatusCode(), response.getAllHeaders(), responseBody, new HttpResponseException(status.getStatusCode(), status.getReasonPhrase())); } else { // 成功的状况 sendSuccessMessage(status.getStatusCode(), response.getAllHeaders(), responseBody); } } } } /** * Returns byte array of response HttpEntity contents * * @param entity can be null * @return response entity body or null * @throws java.io.IOException if reading entity or creating byte array failed */ byte[] getResponseData(HttpEntity entity) throws IOException { byte[] responseBody = null; if (entity != null) { InputStream instream = entity.getContent(); // 从entity中读取字节流 if (instream != null) { long contentLength = entity.getContentLength(); if (contentLength > Integer.MAX_VALUE) { throw new IllegalArgumentException("HTTP entity too large to be buffered in memory"); } int buffersize = (contentLength <= 0) ? BUFFER_SIZE : (int) contentLength; try { ByteArrayBuffer buffer = new ByteArrayBuffer(buffersize); try { byte[] tmp = new byte[BUFFER_SIZE]; int l, count = 0; // do not send messages if request has been cancelled while ((l = instream.read(tmp)) != -1 && !Thread.currentThread().isInterrupted()) { count += l; buffer.append(tmp, 0, l); sendProgressMessage(count, (int) (contentLength <= 0 ? 1 : contentLength)); } } finally { AsyncHttpClient.silentCloseInputStream(instream); AsyncHttpClient.endEntityViaReflection(entity); } responseBody = buffer.toByteArray(); } catch (OutOfMemoryError e) { System.gc(); throw new IOException("File too large to fit into available memory"); } } } return responseBody; }
onXXX方法除了onSuccess和onFailure外都作了默认实现即啥也不作,因此继承至它的子类至少要实现这2个方法,其余的方法你能够选择性实现。
接下来咱们看看TextHttpResponseHandler子类的实现,关键代码以下:
@Override // 对上述2个方法的重载,其中将byte[]经过getResponseString方法转化成了String对象 public void onSuccess(int statusCode, Header[] headers, byte[] responseBytes) { onSuccess(statusCode, headers, getResponseString(responseBytes, getCharset())); } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBytes, Throwable throwable) { onFailure(statusCode, headers, getResponseString(responseBytes, getCharset()), throwable); } /** * Attempts to encode response bytes as string of set encoding * * @param charset charset to create string with * @param stringBytes response bytes * @return String of set encoding or null */ public static String getResponseString(byte[] stringBytes, String charset) { try { String toReturn = (stringBytes == null) ? null : new String(stringBytes, charset); if (toReturn != null && toReturn.startsWith(UTF8_BOM)) { return toReturn.substring(1); } return toReturn; } catch (UnsupportedEncodingException e) { Log.e(LOG_TAG, "Encoding response into string failed", e); return null; } }
说白了,也就是在父类基础上多了一层处理,将byte[]根据特定的编码转化成String而已,相似的JsonHttpResponseHandler又在此基础上
将String转化成JSONObject或JSONArray,细节不赘述。
ResponseHandler介绍完了,这里咱们提下RetryHandler,这个类也很简单,根据内部的白/黑名单等规则来肯定是否要retry。
AsyncHttpClient固然也提供了对Cookie的支持,默认是保存在Android的SharedPreferences中,具体代码见PersistentCookieStore。
还有一个功能丰富的RequestParams类,据此你不只能够为GET/POST方法提供参数,甚至你能够上传本地文件到server端。