上一篇文章从功能和用法上对AsyncHttpClient做了个大致介绍,今天我们和以往一样,从内部实现、原理的角度带领大家看看

其工作机制,以便加深理解。写程序越多,我发现每接触一个新东西,都会有强烈的想知道它内部怎么工作的冲动。可能只有知道了

内部原理能更容易写出高质量的代码吧。

  我大概浏览了下其代码,关键部分可以分为这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 DefaultHttpClientprivate final HttpContext httpContext;private ExecutorService threadPool; // 执行网络请求的线程池private final Map<Context, List<RequestHandle>> requestMap; // 与Android Context对应的请求mapprivate final Map<String, String> clientHeaderMap; // 客户端的请求header mapprivate boolean isUrlEncodingEnabled = true; // 允许url encoding

接下来看看各种ctor,如下:

    /*** Creates a new AsyncHttpClient with default constructor arguments values*/public AsyncHttpClient() { // 一般客户端代码中都直接调用这个版本的ctorthis(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() {@Overridepublic 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() {@Overridepublic 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() {@Overridepublic 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至少是个RunnableRequestHandle requestHandle = new RequestHandle(request);if (context != null) { // 如果Android context非空的话,做一些关联操作,后面可以通过context来取消request的执行// Add request to request mapList<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到线程池的Runnableprivate 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...
    }@Overridepublic 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()) { // 检查againreturn;}if (responseHandler != null) { // 没取消的情况下,发送完成消息responseHandler.sendFinishMessage();}if (isCancelled()) {return;}// Carry out post-processing for this request.onPostProcessRequest(this); // 处理了请求之后的callbackisFinished = true; // 设置为true表示这个请求执行完毕了}private void makeRequest() throws IOException { // 发送一次请求if (isCancelled()) {return;}// Fixes #115if (request.getURI().getScheme() == null) {// subclass of IOException so processed in the callerthrow new MalformedURLException("No valid URI scheme was provided");}// 执行请求获得responseHttpResponse 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); // 发送获得的responseif (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 failurecause = 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=5255cause = new IOException("NPE in HttpClient: " + e.getMessage());retry = retryHandler.retryRequest(cause, ++executionCount, context);} catch (IOException e) {if (isCancelled()) {// Eating exception, as the request was cancelledreturn;}cause = e;retry = retryHandler.retryRequest(cause, ++executionCount, context);}                // 各种异常的情况下,计算retry,看还是否需要retryif (retry && (responseHandler != null)) { // 需要retry的时候,发送retry消息并附带第几次retry了responseHandler.sendRetryMessage(executionCount);}}} catch (Exception e) {// catch anything else to ensure failure message is propagatedLog.e("AsyncHttpRequest", "Unhandled exception origin cause", e);            // 其他的所有不在上述catch里的异常都在这里统一包装成IOException,在最后抛出cause = new IOException("Unhandled exception: " + e.getMessage());}// cleaned up to throw IOExceptionthrow (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() { // 不指定looperthis(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}                                 // 关联的线程中,而不是请求发生的线程池里的线程中@Overridepublic void setUseSynchronousMode(boolean sync) {// A looper must be prepared before setting asynchronous mode.if (!sync && this.looper == null) {sync = true; // 一种错误的情况,强制使用同步modeLog.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 taskshandler = 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;}@Overridepublic void handleMessage(Message msg) { // 一个简单的Handler,其handleMessage delegate给了mRespondermResponder.handleMessage(msg);}}// Methods which emulate android's Handler and Message methodsprotected 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的解析过程,代码如下:

    @Overridepublic void sendResponseMessage(HttpResponse response) throws IOException {// do not process if request has been cancelledif (!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 processif (!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 cancelledwhile ((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()));}@Overridepublic 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端。

  到此为止,AsyncHttpClient关键部分的代码已基本分析完毕了,剩下的还需要大家自己在项目中多多实践,enjoy。。。

原文: http://www.cnblogs.com/xiaoweiz/p/3918042.html

AsyncHttpClient 源码分析相关推荐

  1. AsyncHttpClient源码分析-基于Netty的连接池实现

    原文地址:asynchttpclient源码分析-基于Netty的连接池实现 最近项目重构,有了个机会更多接触一个有别于HttpAsyncClient的异步网络框架AsyncHttpClient,是个 ...

  2. 【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析

    目录[阅读时间:约10分钟] 一.概述 二.对比: gorilla/mux与net/http DefaultServeMux 三.简单使用 四.源码简析 1.NewRouter函数 2.HandleF ...

  3. SpringBoot-web开发(四): SpringMVC的拓展、接管(源码分析)

    [SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) SpringBoot-web开发(二): 页面和图标定制(源码分析) SpringBo ...

  4. SpringBoot-web开发(二): 页面和图标定制(源码分析)

    [SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) 目录 一.首页 1. 源码分析 2. 访问首页测试 二.动态页面 1. 动态资源目录t ...

  5. SpringBoot-web开发(一): 静态资源的导入(源码分析)

    目录 方式一:通过WebJars 1. 什么是webjars? 2. webjars的使用 3. webjars结构 4. 解析源码 5. 测试访问 方式二:放入静态资源目录 1. 源码分析 2. 测 ...

  6. Yolov3Yolov4网络结构与源码分析

    Yolov3&Yolov4网络结构与源码分析 从2018年Yolov3年提出的两年后,在原作者声名放弃更新Yolo算法后,俄罗斯的Alexey大神扛起了Yolov4的大旗. 文章目录 论文汇总 ...

  7. ViewGroup的Touch事件分发(源码分析)

    Android中Touch事件的分发又分为View和ViewGroup的事件分发,View的touch事件分发相对比较简单,可参考 View的Touch事件分发(一.初步了解) View的Touch事 ...

  8. View的Touch事件分发(二.源码分析)

    Android中Touch事件的分发又分为View和ViewGroup的事件分发,先来看简单的View的touch事件分发. 主要分析View的dispatchTouchEvent()方法和onTou ...

  9. MyBatis原理分析之四:一次SQL查询的源码分析

    上回我们讲到Mybatis加载相关的配置文件进行初始化,这回我们讲一下一次SQL查询怎么进行的. 准备工作 Mybatis完成一次SQL查询需要使用的代码如下: Java代码   String res ...

最新文章

  1. C#函数式编程之可选值
  2. python1000个常用代码-1000个常用的Python库和示例代码
  3. 系统学习Spring之Spring in action(二)
  4. Mybatis中重要的小知识点
  5. 为sharepoint 2013 增加切换账户登陆菜单
  6. pd17虚拟机启动器怎么生成?快来看看吧
  7. 第二阶段团队冲刺第九天
  8. LeetCode 368. 最大整除子集(动态规划)
  9. window10查看内存情况
  10. ojdbc7加入本地maven仓库
  11. 关于电子计算机的热点,电脑如何变热点?8款电脑wifi热点软件推荐
  12. Centos8上安装中文字符集zh_CN.UTF-8
  13. 2G、 3G、 4G、5G的区别
  14. 大叔配萝莉/正太的电影一般都不会差。。。
  15. JAVA dwg转pdf的正确解法
  16. android高斯模糊平均值,高斯模糊
  17. Pytest(17)运行未提交的git(pytest-picked)
  18. 华硕t100ta linux,华硕T100TA个人补充评测
  19. 逻辑回归(LR)原理讲解
  20. 2022年奢侈品行业研究报告

热门文章

  1. 策略(strategy)模式
  2. 关于.net Microsoft.Office.Interop.Word组建操作word的问题,如何控制word表格单元格内部段落的样式。...
  3. 判断是否是闰年的方法,很简单噢
  4. c++学习笔记之类的应用
  5. Go 语言web 框架 Gin 练习 7
  6. 信号处理:希尔伯特黄变换
  7. Android应用开发--MP3音乐播放器代码实现(二)
  8. 用matlab绘制升余弦函数
  9. [云炬创业管理笔记]第一章讨论1
  10. [云炬创业基础笔记]第二章创业者测试8