AsyncHttpClient 源码分析

移动开发 Android
上一篇文章从功能和用法上对AsyncHttpClient做了个大致介绍,今天我们和以往一样,从内部实现、原理的角度带领大家看看其工作机制,以便加深理解。写程序越多,我发现每接触一个新东西,都会有强烈的想知道它内部怎么工作的冲动。可能只有知道了.

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

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

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

我大概浏览了下其代码,关键部分可以分为这4个模块:

1. AsyncHttpClient自己一个模块;

2. AsyncHttpRequest和RequestHandler一个模块;

3. AsyncHttpResponseHandler及其各种特定子类一个模块;

4. RetryHandler,自动重试机制。

我们可以很清楚的看出门道来,大体是按照client、request、response,这样的方式组织的。接下来我们的代码分析也就按照这个顺序进行。

先来说AsyncHttpClient,来看其关键字段和ctor,代码如下:

  1. public static final String LOG_TAG = "AsyncHttpClient"
  2.  
  3.     public static final String HEADER_CONTENT_TYPE = "Content-Type"
  4.     public static final String HEADER_CONTENT_RANGE = "Content-Range"
  5.     public static final String HEADER_CONTENT_ENCODING = "Content-Encoding"
  6.     public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition"
  7.     public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding"
  8.     public static final String ENCODING_GZIP = "gzip"
  9.  
  10.     public static final int DEFAULT_MAX_CONNECTIONS = 10
  11.     public static final int DEFAULT_SOCKET_TIMEOUT = 10 * 1000
  12.     public static final int DEFAULT_MAX_RETRIES = 5
  13.     public static final int DEFAULT_RETRY_SLEEP_TIME_MILLIS = 1500
  14.     public static final int DEFAULT_SOCKET_BUFFER_SIZE = 8192
  15.  
  16.     private int maxConnections = DEFAULT_MAX_CONNECTIONS; 
  17.     private int connectTimeout = DEFAULT_SOCKET_TIMEOUT; 
  18.     private int responseTimeout = DEFAULT_SOCKET_TIMEOUT; // 各种参数设置 
  19.  
  20.     private final DefaultHttpClient httpClient; // 包装的Apache DefaultHttpClient 
  21.     private final HttpContext httpContext; 
  22.     private ExecutorService threadPool; // 执行网络请求的线程池 
  23.     private final Map<Context, List<RequestHandle>> requestMap; // 与Android Context对应的请求map 
  24.     private final Map<String, String> clientHeaderMap; // 客户端的请求header map 
  25.     private boolean isUrlEncodingEnabled = true// 允许url encoding 

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

  1.     /** 
  2.      * Creates a new AsyncHttpClient with default constructor arguments values 
  3.      */ 
  4.     public AsyncHttpClient() { // 一般客户端代码中都直接调用这个版本的ctor 
  5.         this(false80443); 
  6.     } 
  7.  
  8.     /** 
  9.      * Creates a new AsyncHttpClient. 
  10.      * 
  11.      * @param httpPort non-standard HTTP-only port 
  12.      */ 
  13.     public AsyncHttpClient(int httpPort) { 
  14.         this(false, httpPort, 443); 
  15.     } 
  16.  
  17.     /** 
  18.      * Creates a new AsyncHttpClient. 
  19.      * 
  20.      * @param httpPort  non-standard HTTP-only port 
  21.      * @param httpsPort non-standard HTTPS-only port 
  22.      */ 
  23.     public AsyncHttpClient(int httpPort, int httpsPort) { 
  24.         this(false, httpPort, httpsPort); 
  25.     } 
  26.  
  27.     /** 
  28.      * Creates new AsyncHttpClient using given params 
  29.      * 
  30.      * @param fixNoHttpResponseException Whether to fix or not issue, by omitting SSL verification 
  31.      * @param httpPort                   HTTP port to be used, must be greater than 0 
  32.      * @param httpsPort                  HTTPS port to be used, must be greater than 0 
  33.      */ 
  34.     public AsyncHttpClient(boolean fixNoHttpResponseException, int httpPort, int httpsPort) { 
  35.         this(getDefaultSchemeRegistry(fixNoHttpResponseException, httpPort, httpsPort)); 
  36.     } 
  37.  
  38.     /** 
  39.      * Returns default instance of SchemeRegistry 
  40.      * 
  41.      * @param fixNoHttpResponseException Whether to fix or not issue, by omitting SSL verification 
  42.      * @param httpPort                   HTTP port to be used, must be greater than 0 
  43.      * @param httpsPort                  HTTPS port to be used, must be greater than 0 
  44.      */ 
  45.     private static SchemeRegistry getDefaultSchemeRegistry(boolean fixNoHttpResponseException, int httpPort, int httpsPort) { 
  46.         if (fixNoHttpResponseException) { // 如果你请求的url是https的,并且遇到了SSL验证之类的错误,那么你应该将此值设为true试试 
  47.             Log.d(LOG_TAG, "Beware! Using the fix is insecure, as it doesn't verify SSL certificates."); 
  48.         } 
  49.  
  50.         if (httpPort < 1) { 
  51.             httpPort = 80
  52.             Log.d(LOG_TAG, "Invalid HTTP port number specified, defaulting to 80"); 
  53.         } 
  54.  
  55.         if (httpsPort < 1) { 
  56.             httpsPort = 443
  57.             Log.d(LOG_TAG, "Invalid HTTPS port number specified, defaulting to 443"); 
  58.         } 
  59.  
  60.         // Fix to SSL flaw in API < ICS 
  61.         // See https://code.google.com/p/android/issues/detail?id=13117 
  62.         SSLSocketFactory sslSocketFactory; 
  63.         if (fixNoHttpResponseException) { // 感兴趣的同学可自行看看MySSLSocketFactory的实现,基本上是省略了SSL验证环节 
  64.             sslSocketFactory = MySSLSocketFactory.getFixedSocketFactory(); 
  65.         } else { 
  66.             sslSocketFactory = SSLSocketFactory.getSocketFactory(); 
  67.         } 
  68.  
  69.         SchemeRegistry schemeRegistry = new SchemeRegistry(); 
  70.         schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), httpPort)); 
  71.         schemeRegistry.register(new Scheme("https", sslSocketFactory, httpsPort)); 
  72.  
  73.         return schemeRegistry; 
  74.     } 
  75.  
  76.     /** 
  77.      * Creates a new AsyncHttpClient. 
  78.      * 
  79.      * @param schemeRegistry SchemeRegistry to be used 
  80.      */ 
  81.     public AsyncHttpClient(SchemeRegistry schemeRegistry) { // 最终调到的是这个版本。。。 
  82.  
  83.         BasicHttpParams httpParams = new BasicHttpParams(); 
  84.         // 接下来是设置各种参数。。。 
  85.         ConnManagerParams.setTimeout(httpParams, connectTimeout); 
  86.         ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(maxConnections)); 
  87.         ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS); 
  88.  
  89.         HttpConnectionParams.setSoTimeout(httpParams, responseTimeout); 
  90.         HttpConnectionParams.setConnectionTimeout(httpParams, connectTimeout); 
  91.         HttpConnectionParams.setTcpNoDelay(httpParams, true); 
  92.         HttpConnectionParams.setSocketBufferSize(httpParams, DEFAULT_SOCKET_BUFFER_SIZE); 
  93.          
  94.         HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1); 
  95.  
  96.         ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(httpParams, schemeRegistry); 
  97.         // 初始化关键字段 
  98.         threadPool = getDefaultThreadPool(); 
  99.         requestMap = Collections.synchronizedMap(new WeakHashMap<Context, List<RequestHandle>>()); 
  100.         clientHeaderMap = new HashMap<String, String>(); 
  101.  
  102.         httpContext = new SyncBasicHttpContext(new BasicHttpContext()); 
  103.         httpClient = new DefaultHttpClient(cm, httpParams); 
  104.         httpClient.addRequestInterceptor(new HttpRequestInterceptor() { 
  105.             @Override 
  106.             public void process(HttpRequest request, HttpContext context) { 
  107.                 if (!request.containsHeader(HEADER_ACCEPT_ENCODING)) { 
  108.                     request.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP); 
  109.                 } 
  110.                 for (String header : clientHeaderMap.keySet()) { 
  111.                     if (request.containsHeader(header)) { 
  112.                         Header overwritten = request.getFirstHeader(header); 
  113.                         Log.d(LOG_TAG, 
  114.                                 String.format("Headers were overwritten! (%s | %s) overwrites (%s | %s)"
  115.                                         header, clientHeaderMap.get(header), 
  116.                                         overwritten.getName(), overwritten.getValue()) 
  117.                         ); 
  118.  
  119.                         //remove the overwritten header 
  120.                         request.removeHeader(overwritten); 
  121.                     } 
  122.                     request.addHeader(header, clientHeaderMap.get(header)); 
  123.                 } 
  124.             } 
  125.         }); 
  126.  
  127.         httpClient.addResponseInterceptor(new HttpResponseInterceptor() { 
  128.             @Override 
  129.             public void process(HttpResponse response, HttpContext context) { 
  130.                 final HttpEntity entity = response.getEntity(); 
  131.                 if (entity == null) { 
  132.                     return
  133.                 } 
  134.                 final Header encoding = entity.getContentEncoding(); 
  135.                 if (encoding != null) { 
  136.                     for (HeaderElement element : encoding.getElements()) { 
  137.                         if (element.getName().equalsIgnoreCase(ENCODING_GZIP)) { 
  138.                             response.setEntity(new InflatingEntity(entity)); 
  139.                             break
  140.                         } 
  141.                     } 
  142.                 } 
  143.             } 
  144.         }); 
  145.  
  146.         httpClient.addRequestInterceptor(new HttpRequestInterceptor() { 
  147.             @Override 
  148.             public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { 
  149.                 AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE); 
  150.                 CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute( 
  151.                         ClientContext.CREDS_PROVIDER); 
  152.                 HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST); 
  153.  
  154.                 if (authState.getAuthScheme() == null) { 
  155.                     AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort()); 
  156.                     Credentials creds = credsProvider.getCredentials(authScope); 
  157.                     if (creds != null) { 
  158.                         authState.setAuthScheme(new BasicScheme()); 
  159.                         authState.setCredentials(creds); 
  160.                     } 
  161.                 } 
  162.             } 
  163.         }, 0); 
  164.         // 设置重试Handler,会在合适的情况下自动重试 
  165.         httpClient.setHttpRequestRetryHandler(new RetryHandler(DEFAULT_MAX_RETRIES, DEFAULT_RETRY_SLEEP_TIME_MILLIS)); 
  166.     } 
  167.  
  168.  
  169. 接下来重要的就是各种HTTP head、get、post、delete方法,它们最终调用的都是sendRequest方法,如下: 
  170. 复制代码 
  171.  
  172.     /** 
  173.      * Puts a new request in queue as a new thread in pool to be executed 
  174.      * 
  175.      * @param client          HttpClient to be used for request, can differ in single requests 
  176.      * @param contentType     MIME body type, for POST and PUT requests, may be null 
  177.      * @param context         Context of Android application, to hold the reference of request 
  178.      * @param httpContext     HttpContext in which the request will be executed 
  179.      * @param responseHandler ResponseHandler or its subclass to put the response into 
  180.      * @param uriRequest      instance of HttpUriRequest, which means it must be of HttpDelete, 
  181.      *                        HttpPost, HttpGet, HttpPut, etc. 
  182.      * @return RequestHandle of future request process 
  183.      */ 
  184.     protected RequestHandle sendRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, 
  185.             String contentType, ResponseHandlerInterface responseHandler, Context context) { 
  186.         if (uriRequest == null) { 
  187.             throw new IllegalArgumentException("HttpUriRequest must not be null"); 
  188.         } 
  189.  
  190.         if (responseHandler == null) { 
  191.             throw new IllegalArgumentException("ResponseHandler must not be null"); 
  192.         } 
  193.  
  194.         if (responseHandler.getUseSynchronousMode()) { 
  195.             throw new IllegalArgumentException("Synchronous ResponseHandler used in AsyncHttpClient. You should create your response handler in a looper thread or use SyncHttpClient instead."); 
  196.         } 
  197.  
  198.         if (contentType != null) { 
  199.             uriRequest.setHeader(HEADER_CONTENT_TYPE, contentType); 
  200.         } 
  201.  
  202.         responseHandler.setRequestHeaders(uriRequest.getAllHeaders()); 
  203.         responseHandler.setRequestURI(uriRequest.getURI()); 
  204.         // 下面的这3行是重点,创建请求,提交请求到线程池,将请求包装到RequestHandle用于之后的取消、管理 
  205.         AsyncHttpRequest request = newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context); 
  206.         threadPool.submit(request); // 能submit说明request至少是个Runnable 
  207.         RequestHandle requestHandle = new RequestHandle(request); 
  208.  
  209.         if (context != null) { // 如果Android context非空的话,做一些关联操作,后面可以通过context来取消request的执行 
  210.             // Add request to request map 
  211.             List<RequestHandle> requestList = requestMap.get(context); 
  212.             synchronized (requestMap) { 
  213.                 if (requestList == null) { 
  214.                     requestList = Collections.synchronizedList(new LinkedList<RequestHandle>()); 
  215.                     requestMap.put(context, requestList); 
  216.                 } 
  217.             } 
  218.  
  219.             if (responseHandler instanceof RangeFileAsyncHttpResponseHandler) 
  220.                 ((RangeFileAsyncHttpResponseHandler) responseHandler).updateRequestHeaders(uriRequest); 
  221.  
  222.             requestList.add(requestHandle); 
  223.  
  224.             Iterator<RequestHandle> iterator = requestList.iterator(); 
  225.             while (iterator.hasNext()) { 
  226.                 if (iterator.next().shouldBeGarbageCollected()) { 
  227.                     iterator.remove(); // 清理已经完成/取消了的请求 
  228.                 } 
  229.             } 
  230.         } 
  231.  
  232.         return requestHandle; 
  233.     } 

看到了吧,发送请求的过程其实重点是创建请求,然后submit到线程池,剩下的事情就交给线程池自己处理了,我们只需要坐等被调用。

来看看创建请求的方法,代码如下:

  1. /** 
  2.      * Instantiate a new asynchronous HTTP request for the passed parameters. 
  3.      * 
  4.      * @param client          HttpClient to be used for request, can differ in single requests 
  5.      * @param contentType     MIME body type, for POST and PUT requests, may be null 
  6.      * @param context         Context of Android application, to hold the reference of request 
  7.      * @param httpContext     HttpContext in which the request will be executed 
  8.      * @param responseHandler ResponseHandler or its subclass to put the response into 
  9.      * @param uriRequest      instance of HttpUriRequest, which means it must be of HttpDelete, 
  10.      *                        HttpPost, HttpGet, HttpPut, etc. 
  11.      * @return AsyncHttpRequest ready to be dispatched 
  12.      */ 
  13.     protected AsyncHttpRequest newAsyncHttpRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType, ResponseHandlerInterface responseHandler, Context context) { 
  14.         return new AsyncHttpRequest(client, httpContext, uriRequest, responseHandler); 
  15.     } 

紧接着我们看看AsyncHttpRequest的实现:

  1. /** 
  2.  * Internal class, representing the HttpRequest, done in asynchronous manner 
  3.  */ 
  4. public class AsyncHttpRequest implements Runnable { // 这就是submit到线程池的Runnable 
  5.     private final AbstractHttpClient client; 
  6.     private final HttpContext context; 
  7.     private final HttpUriRequest request; 
  8.     private final ResponseHandlerInterface responseHandler; 
  9.     private int executionCount; 
  10.     private boolean isCancelled; 
  11.     private boolean cancelIsNotified; 
  12.     private boolean isFinished; 
  13.     private boolean isRequestPreProcessed; 
  14.  
  15.     public AsyncHttpRequest(AbstractHttpClient client, HttpContext context, HttpUriRequest request, ResponseHandlerInterface responseHandler) { 
  16.         this.client = client; 
  17.         this.context = context; 
  18.         this.request = request; 
  19.         this.responseHandler = responseHandler; 
  20.     } 
  21.  
  22.     /** 
  23.      * This method is called once by the system when the request is about to be 
  24.      * processed by the system. The library makes sure that a single request 
  25.      * is pre-processed only once. 
  26.      * 
  27.      * Please note: pre-processing does NOT run on the main thread, and thus 
  28.      * any UI activities that you must perform should be properly dispatched to 
  29.      * the app's UI thread. 
  30.      * 
  31.      * @param request The request to pre-process 
  32.      */ 
  33.     public void onPreProcessRequest(AsyncHttpRequest request) { 
  34.         // default action is to do nothing... 
  35.     } 
  36.  
  37.     /** 
  38.      * This method is called once by the system when the request has been fully 
  39.      * sent, handled and finished. The library makes sure that a single request 
  40.      * is post-processed only once. 
  41.      * 
  42.      * Please note: post-processing does NOT run on the main thread, and thus 
  43.      * any UI activities that you must perform should be properly dispatched to 
  44.      * the app's UI thread. 
  45.      * 
  46.      * @param request The request to post-process 
  47.      */ 
  48.     public void onPostProcessRequest(AsyncHttpRequest request) { 
  49.         // default action is to do nothing... 
  50.     } 
  51.  
  52.     @Override 
  53.     public void run() { // 这是在线程池中执行的方法,我们重点看看 
  54.         if (isCancelled()) { // 检测,如果已经取消了则直接返回,下面的代码有好多次做这个检测,因为你永远不知道什么时候会被取消 
  55.             return;          // 同时也说明了我们的Request是支持取消的 
  56.         } 
  57.  
  58.         // Carry out pre-processing for this request only once. 
  59.         if (!isRequestPreProcessed) { 
  60.             isRequestPreProcessed = true
  61.             onPreProcessRequest(this); // callback接口,在一次请求中只调用一次 
  62.         } 
  63.  
  64.         if (isCancelled()) { // 再次检查 
  65.             return
  66.         } 
  67.  
  68.         if (responseHandler != null) { 
  69.             responseHandler.sendStartMessage(); // 发送开始请求消息 
  70.         } 
  71.  
  72.         if (isCancelled()) { // 检查 
  73.             return
  74.         } 
  75.  
  76.         try { 
  77.             makeRequestWithRetries(); // 带自动retry机制的请求 
  78.         } catch (IOException e) { 
  79.             if (!isCancelled() && responseHandler != null) { 
  80.                 responseHandler.sendFailureMessage(0nullnull, e); // 在没取消的情况下,发送失败消息 
  81.             } else { 
  82.                 Log.e("AsyncHttpRequest""makeRequestWithRetries returned error, but handler is null", e); 
  83.             } 
  84.         } 
  85.  
  86.         if (isCancelled()) { // 检查again 
  87.             return
  88.         } 
  89.  
  90.         if (responseHandler != null) { // 没取消的情况下,发送完成消息 
  91.             responseHandler.sendFinishMessage(); 
  92.         } 
  93.  
  94.         if (isCancelled()) { 
  95.             return
  96.         } 
  97.  
  98.         // Carry out post-processing for this request. 
  99.         onPostProcessRequest(this); // 处理了请求之后的callback 
  100.  
  101.         isFinished = true// 设置为true表示这个请求执行完毕了 
  102.     } 
  103.  
  104.     private void makeRequest() throws IOException { // 发送一次请求 
  105.         if (isCancelled()) { 
  106.             return
  107.         } 
  108.  
  109.         // Fixes #115 
  110.         if (request.getURI().getScheme() == null) { 
  111.             // subclass of IOException so processed in the caller 
  112.             throw new MalformedURLException("No valid URI scheme was provided"); 
  113.         } 
  114.         // 执行请求获得response 
  115.         HttpResponse response = client.execute(request, context); 
  116.  
  117.         if (isCancelled() || responseHandler == null) { 
  118.             return
  119.         } 
  120.  
  121.         // Carry out pre-processing for this response. 
  122.         responseHandler.onPreProcessResponse(responseHandler, response); // 处理response前 
  123.  
  124.         if (isCancelled()) { 
  125.             return
  126.         } 
  127.  
  128.         // The response is ready, handle it. 
  129.         responseHandler.sendResponseMessage(response); // 发送获得的response 
  130.  
  131.         if (isCancelled()) { 
  132.             return
  133.         } 
  134.  
  135.         // Carry out post-processing for this response. 
  136.         responseHandler.onPostProcessResponse(responseHandler, response); // 处理response后 
  137.     } 
  138.  
  139.     private void makeRequestWithRetries() throws IOException { 
  140.         boolean retry = true
  141.         IOException cause = null
  142.         HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler(); 
  143.         try { 
  144.             while (retry) { // 注意这个循环,当retry为false的时候退出 
  145.                 try { 
  146.                     makeRequest(); 
  147.                     return// 请求成功的话,直接返回 
  148.                 } catch (UnknownHostException e) { 
  149.                     // switching between WI-FI and mobile data networks can cause a retry which then results in an UnknownHostException 
  150.                     // while the WI-FI is initialising. The retry logic will be invoked here, if this is NOT the first retry 
  151.                     // (to assist in genuine cases of unknown host) which seems better than outright failure 
  152.                     cause = new IOException("UnknownHostException exception: " + e.getMessage()); 
  153.                     retry = (executionCount > 0) && retryHandler.retryRequest(cause, ++executionCount, context); 
  154.                 } catch (NullPointerException e) { 
  155.                     // there's a bug in HttpClient 4.0.x that on some occasions causes 
  156.                     // DefaultRequestExecutor to throw an NPE, see 
  157.                     // http://code.google.com/p/android/issues/detail?id=5255 
  158.                     cause = new IOException("NPE in HttpClient: " + e.getMessage()); 
  159.                     retry = retryHandler.retryRequest(cause, ++executionCount, context); 
  160.                 } catch (IOException e) { 
  161.                     if (isCancelled()) { 
  162.                         // Eating exception, as the request was cancelled 
  163.                         return
  164.                     } 
  165.                     cause = e; 
  166.                     retry = retryHandler.retryRequest(cause, ++executionCount, context); 
  167.                 } 
  168.                 // 各种异常的情况下,计算retry,看还是否需要retry 
  169.                 if (retry && (responseHandler != null)) { // 需要retry的时候,发送retry消息并附带第几次retry了 
  170.                     responseHandler.sendRetryMessage(executionCount); 
  171.                 } 
  172.             } 
  173.         } catch (Exception e) { 
  174.             // catch anything else to ensure failure message is propagated 
  175.             Log.e("AsyncHttpRequest""Unhandled exception origin cause", e); 
  176.             // 其他的所有不在上述catch里的异常都在这里统一包装成IOException,在最后抛出 
  177.             cause = new IOException("Unhandled exception: " + e.getMessage()); 
  178.         } 
  179.  
  180.         // cleaned up to throw IOException 
  181.         throw (cause); // 抛出,以便上层代码知道发生了什么 
  182.     } 
  183.  
  184.     public boolean isCancelled() { 
  185.         if (isCancelled) { 
  186.             sendCancelNotification(); 
  187.         } 
  188.         return isCancelled; 
  189.     } 
  190.  
  191.     private synchronized void sendCancelNotification() { 
  192.         if (!isFinished && isCancelled && !cancelIsNotified) { 
  193.             cancelIsNotified = true
  194.             if (responseHandler != null
  195.                 responseHandler.sendCancelMessage(); 
  196.         } 
  197.     } 
  198.  
  199.     public boolean isDone() { 
  200.         return isCancelled() || isFinished; 
  201.     } 
  202.  
  203.     public boolean cancel(boolean mayInterruptIfRunning) { 
  204.         isCancelled = true
  205.         request.abort(); 
  206.         return isCancelled(); 
  207.     } 

紧接着,我们大概提下RequestHandle,它只是一个持有AsyncHttpRequest对象的弱引用,其方法内部都delegate给了AsyncHttpRequest,

非常简单,感兴趣的同学可自行阅读。

看完了Request,接下来该看看各种Response了,他们都实现了ResponseHandlerInterface接口,这里我们重点看下AsyncHttpResponseHandler,

因为它是后面所有更具体的子类的基础,其ctor代码如下:

  1. /** 
  2.     * Creates a new AsyncHttpResponseHandler 
  3.     */ 
  4.    public AsyncHttpResponseHandler() { // 不指定looper 
  5.        this(null); 
  6.    } 
  7.  
  8.    /** 
  9.     * Creates a new AsyncHttpResponseHandler with a user-supplied looper. If 
  10.     * the passed looper is null, the looper attached to the current thread will 
  11.     * be used. 
  12.     * 
  13.     * @param looper The looper to work with 
  14.     */ 
  15.    public AsyncHttpResponseHandler(Looper looper) { // 如果没指定looper的话,会用当前线程的looper顶替 
  16.        this.looper = looper == null ? Looper.myLooper() : looper; 
  17.        // Use asynchronous mode by default. 
  18.        setUseSynchronousMode(false); // 默认是异步的方式,这里异步的意思是指对response的处理发生在与looper 
  19.    }                                 // 关联的线程中,而不是请求发生的线程池里的线程中 
  20.  
  21.    @Override 
  22.    public void setUseSynchronousMode(boolean sync) { 
  23.        // A looper must be prepared before setting asynchronous mode. 
  24.        if (!sync && this.looper == null) { 
  25.            sync = true// 一种错误的情况,强制使用同步mode 
  26.            Log.w(LOG_TAG, "Current thread has not called Looper.prepare(). Forcing synchronous mode."); 
  27.        } 
  28.  
  29.        // If using asynchronous mode. 
  30.        if (!sync && handler == null) { // 初始化handler 
  31.            // Create a handler on current thread to submit tasks 
  32.            handler = new ResponderHandler(thisthis.looper); 
  33.        } else if (sync && handler != null) { 
  34.            // TODO: Consider adding a flag to remove all queued messages. 
  35.            handler = null
  36.        } 
  37.  
  38.        useSynchronousMode = sync; 
  39.    } 

一般来说,我们会直接在UI线程中调用无参版本的ctor,也就是说response是和UI线程关联的,所有对其的处理handleMessage是发生

在UI线程中的。如果你想用response的结果来更新UI则这是正确的方式。

接着我们看看和处理response相关的代码:

  1. /** 
  2.      * Avoid leaks by using a non-anonymous handler class. 
  3.      */ 
  4.     private static class ResponderHandler extends Handler { 
  5.         private final AsyncHttpResponseHandler mResponder; 
  6.  
  7.         ResponderHandler(AsyncHttpResponseHandler mResponder, Looper looper) { 
  8.             super(looper); 
  9.             this.mResponder = mResponder; 
  10.         } 
  11.  
  12.         @Override 
  13.         public void handleMessage(Message msg) { // 一个简单的Handler,其handleMessage delegate给了mResponder 
  14.             mResponder.handleMessage(msg); 
  15.         } 
  16.     } 
  17.  
  18.     // Methods which emulate android's Handler and Message methods 
  19.     protected void handleMessage(Message message) { // 对各种message的处理,回调各种onXXX方法 
  20.         Object[] response; 
  21.  
  22.         switch (message.what) { 
  23.             case SUCCESS_MESSAGE: 
  24.                 response = (Object[]) message.obj; 
  25.                 if (response != null && response.length >= 3) { 
  26.                     onSuccess((Integer) response[0], (Header[]) response[1], (byte[]) response[2]); 
  27.                 } else { 
  28.                     Log.e(LOG_TAG, "SUCCESS_MESSAGE didn't got enough params"); 
  29.                 } 
  30.                 break
  31.             case FAILURE_MESSAGE: 
  32.                 response = (Object[]) message.obj; 
  33.                 if (response != null && response.length >= 4) { 
  34.                     onFailure((Integer) response[0], (Header[]) response[1], (byte[]) response[2], (Throwable) response[3]); 
  35.                 } else { 
  36.                     Log.e(LOG_TAG, "FAILURE_MESSAGE didn't got enough params"); 
  37.                 } 
  38.                 break
  39.             case START_MESSAGE: 
  40.                 onStart(); 
  41.                 break
  42.             case FINISH_MESSAGE: 
  43.                 onFinish(); 
  44.                 break
  45.             case PROGRESS_MESSAGE: 
  46.                 response = (Object[]) message.obj; 
  47.                 if (response != null && response.length >= 2) { 
  48.                     try { 
  49.                         onProgress((Integer) response[0], (Integer) response[1]); 
  50.                     } catch (Throwable t) { 
  51.                         Log.e(LOG_TAG, "custom onProgress contains an error", t); 
  52.                     } 
  53.                 } else { 
  54.                     Log.e(LOG_TAG, "PROGRESS_MESSAGE didn't got enough params"); 
  55.                 } 
  56.                 break
  57.             case RETRY_MESSAGE: 
  58.                 response = (Object[]) message.obj; 
  59.                 if (response != null && response.length == 1) { 
  60.                     onRetry((Integer) response[0]); 
  61.                 } else { 
  62.                     Log.e(LOG_TAG, "RETRY_MESSAGE didn't get enough params"); 
  63.                 } 
  64.                 break
  65.             case CANCEL_MESSAGE: 
  66.                 onCancel(); 
  67.                 break
  68.         } 
  69.     } 
  70.  
  71.     protected void sendMessage(Message msg) { 
  72.         if (getUseSynchronousMode() || handler == null) { 
  73.             handleMessage(msg); // 如果是同步的方式,则handleMessage发生在调用sendMessage的线程中 
  74.         } else if (!Thread.currentThread().isInterrupted()) { // do not send messages if request has been cancelled 
  75.             handler.sendMessage(msg); // 否则发生在与handler关联的线程中,一般多为UI线程 
  76.         } 
  77.     } 

代码中各种sendXXXMessage都会调用这里的sendMessage方法,只是构造的msg的what、obj不同而已。而sendXXXMessage方法

会在request的不同阶段自动被调用,详见AsyncHttpRequest中。下一步我们看眼对response的解析过程,代码如下:

  1. @Override 
  2.     public void sendResponseMessage(HttpResponse response) throws IOException { 
  3.         // do not process if request has been cancelled 
  4.         if (!Thread.currentThread().isInterrupted()) { 
  5.             StatusLine status = response.getStatusLine(); 
  6.             byte[] responseBody; 
  7.             responseBody = getResponseData(response.getEntity()); // 将response解析成字节数组 
  8.             // additional cancellation check as getResponseData() can take non-zero time to process 
  9.             if (!Thread.currentThread().isInterrupted()) { 
  10.                 if (status.getStatusCode() >= 300) { // 标志失败的情况 
  11.                     sendFailureMessage(status.getStatusCode(), response.getAllHeaders(), responseBody, new HttpResponseException(status.getStatusCode(), status.getReasonPhrase())); 
  12.                 } else { // 成功的情况 
  13.                     sendSuccessMessage(status.getStatusCode(), response.getAllHeaders(), responseBody); 
  14.                 } 
  15.             } 
  16.         } 
  17.     } 
  18.  
  19.     /** 
  20.      * Returns byte array of response HttpEntity contents 
  21.      * 
  22.      * @param entity can be null 
  23.      * @return response entity body or null 
  24.      * @throws java.io.IOException if reading entity or creating byte array failed 
  25.      */ 
  26.     byte[] getResponseData(HttpEntity entity) throws IOException { 
  27.         byte[] responseBody = null
  28.         if (entity != null) { 
  29.             InputStream instream = entity.getContent(); // 从entity中读取字节流 
  30.             if (instream != null) { 
  31.                 long contentLength = entity.getContentLength(); 
  32.                 if (contentLength > Integer.MAX_VALUE) { 
  33.                     throw new IllegalArgumentException("HTTP entity too large to be buffered in memory"); 
  34.                 } 
  35.                 int buffersize = (contentLength <= 0) ? BUFFER_SIZE : (int) contentLength; 
  36.                 try { 
  37.                     ByteArrayBuffer buffer = new ByteArrayBuffer(buffersize); 
  38.                     try { 
  39.                         byte[] tmp = new byte[BUFFER_SIZE]; 
  40.                         int l, count = 0
  41.                         // do not send messages if request has been cancelled 
  42.                         while ((l = instream.read(tmp)) != -1 && !Thread.currentThread().isInterrupted()) { 
  43.                             count += l; 
  44.                             buffer.append(tmp, 0, l); 
  45.                             sendProgressMessage(count, (int) (contentLength <= 0 ? 1 : contentLength)); 
  46.                         } 
  47.                     } finally { 
  48.                         AsyncHttpClient.silentCloseInputStream(instream); 
  49.                         AsyncHttpClient.endEntityViaReflection(entity); 
  50.                     } 
  51.                     responseBody = buffer.toByteArray(); 
  52.                 } catch (OutOfMemoryError e) { 
  53.                     System.gc(); 
  54.                     throw new IOException("File too large to fit into available memory"); 
  55.                 } 
  56.             } 
  57.         } 
  58.         return responseBody; 
  59.     } 

onXXX方法除了onSuccess和onFailure外都做了默认实现即啥也不做,所以继承至它的子类至少要实现这2个方法,其他的方法你可以选择性实现。

接下来我们看看TextHttpResponseHandler子类的实现,关键代码如下:

  1. @Override // 对上述2个方法的重载,其中将byte[]通过getResponseString方法转化成了String对象 
  2.    public void onSuccess(int statusCode, Header[] headers, byte[] responseBytes) { 
  3.        onSuccess(statusCode, headers, getResponseString(responseBytes, getCharset())); 
  4.    } 
  5.  
  6.    @Override 
  7.    public void onFailure(int statusCode, Header[] headers, byte[] responseBytes, Throwable throwable) { 
  8.        onFailure(statusCode, headers, getResponseString(responseBytes, getCharset()), throwable); 
  9.    } 
  10.  
  11.    /** 
  12.     * Attempts to encode response bytes as string of set encoding 
  13.     * 
  14.     * @param charset     charset to create string with 
  15.     * @param stringBytes response bytes 
  16.     * @return String of set encoding or null 
  17.     */ 
  18.    public static String getResponseString(byte[] stringBytes, String charset) { 
  19.        try { 
  20.            String toReturn = (stringBytes == null) ? null : new String(stringBytes, charset); 
  21.            if (toReturn != null && toReturn.startsWith(UTF8_BOM)) { 
  22.                return toReturn.substring(1); 
  23.            } 
  24.            return toReturn; 
  25.        } catch (UnsupportedEncodingException e) { 
  26.            Log.e(LOG_TAG, "Encoding response into string failed", e); 
  27.            return null
  28.        } 
  29.    } 

说白了,也就是在父类基础上多了一层处理,将byte[]根据特定的编码转化成String而已,类似的JsonHttpResponseHandler又在此基础上

将String转化成JSONObject或JSONArray,细节不赘述。

ResponseHandler介绍完了,这里我们提下RetryHandler,这个类也很简单,根据内部的白/黑名单等规则来确定是否要retry。

AsyncHttpClient当然也提供了对Cookie的支持,默认是保存在Android的SharedPreferences中,具体代码见PersistentCookieStore。

还有一个功能丰富的RequestParams类,据此你不仅可以为GET/POST方法提供参数,甚至你可以上传本地文件到server端。

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

本文链接:http://www.cnblogs.com/xiaoweiz/p/3918042.html

责任编辑:chenqingxiang 来源: cnblogs
相关推荐

2011-03-15 11:33:18

iptables

2011-05-26 10:05:48

MongoDB

2021-11-11 17:40:08

WatchdogAndroid源码分析

2011-05-26 16:18:51

Mongodb

2021-03-23 09:17:58

SpringMVCHttpServletJavaEE

2024-06-13 07:55:19

2021-07-06 09:29:38

Cobar源码AST

2015-08-10 15:12:27

Java实例源码分析

2020-11-19 07:41:51

ArrayBlocki

2021-08-09 07:58:36

Nacos 服务注册源码分析

2020-11-25 14:28:56

DelayedWork

2011-06-28 16:18:24

Qt QObject

2011-08-16 09:34:34

Nginx

2021-09-06 10:34:48

Nacos复制源码

2022-03-18 15:29:02

Harmony鸿蒙架构

2021-05-17 09:50:06

Kubebuilde源码CURD

2021-07-12 08:00:21

Nacos 服务注册源码分析

2021-08-09 11:15:28

MybatisJavaSpring

2023-02-26 08:42:10

源码demouseEffect

2015-07-27 14:57:32

OpenFlow协议Ryu
点赞
收藏

51CTO技术栈公众号