android-async-http AsyncHttpClient

它是专门针对Android在Apache的HttpClient基础上构建的异步的callback-based http client。所有的请求

全在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。

简单来说你只需要3步,

1. 创建一个AsyncHttpClient;

2. (可选的)通过RequestParams对象设置请求参数;

3. 调用AsyncHttpClient的某个get方法,传递你需要的(成功和失败时)callback接口实现,一般都是匿名内部类

,实现了AsyncHttpResponseHandler,类库自己也提供了好些现成的response handler,你一般不需要自己创建一个。

来看看代码如何写:

 1 AsyncHttpClient client = new AsyncHttpClient();
 2 client.get("http://www.google.com", new AsyncHttpResponseHandler() {
 3
 4     @Override
 5     public void onStart() {
 6         // called before request is started
 7     }
 8
 9     @Override
10     public void onSuccess(int statusCode, Header[] headers, byte[] response) {
11         // called when response HTTP status is "200 OK"
12     }
13
14     @Override
15     public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
16         // called when response HTTP status is "4XX" (eg. 401, 403, 404)
17     }
18
19     @Override
20     public void onRetry(int retryNo) {
21         // called when request is retried
22     }
23 });

这里你只需要通过匿名内部类的方式实现AsyncHttpResponseHandler,也可以通过RequestParams来传递各种参数

 1 AsyncHttpClient client = new AsyncHttpClient();
 2 RequestParams params = new RequestParams();
 3 params.put("key", "value");
 4 params.put("more", "data");
 5 client.get("http://www.google.com", params, new
 6     AsyncHttpResponseHandler() {
 7         @Override
 8         public void onSuccess(int statusCode, Header[] headers, byte[] response) {
 9             System.out.println(response);
10         }
11
12         @Override
13         public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
14             Log.d("ERROR", error);
15         }
16     }
17 );

以上的例子是返回的response直接是原生字节流的情况,如果你需要把返回的结果当一个String对待,这时只需要匿名实现一个

TextHttpResponseHandler就行,其继承自AsyncHttpResponse,并将原生的字节流根据指定的encoding转化成了string对象,

代码如下:

 1 AsyncHttpClient client = new AsyncHttpClient();
 2 RequestParams params = new RequestParams();
 3 params.put("key", "value");
 4 params.put("more", "data");
 5 client.get("http://www.google.com", params, new
 6     TextHttpResponseHandler() {
 7         @Override
 8         public void onSuccess(int statusCode, Header[] headers, String response) {
 9             System.out.println(response);
10         }
11
12         @Override
13         public void onFailure(int statusCode, Header[] headers, String responseBody, Throwable error) {
14             Log.d("ERROR", error);
15         }
16     }
17 );

同样的方式,你可以发送json请求,代码如下:

 1 String url = "https://ajax.googleapis.com/ajax/services/search/images";
 2 AsyncHttpClient client = new AsyncHttpClient();
 3 RequestParams params = new RequestParams();
 4 params.put("q", "android");
 5 params.put("rsz", "8");
 6 client.get(url, params, new JsonHttpResponseHandler() {
 7     @Override
 8     public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
 9        // Handle resulting parsed JSON response here
10     }
11     @Override
12     public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
13       // Handle resulting parsed JSON response here
14     }
15 });

返回的response已经自动转化成JSONObject了,当然也支持JSONArray类型,override你需要的那个版本就行。

AsyncHttpClient 源码分析

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(false, 80, 443);
  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     }

接下来重要的就是各种HTTP head、get、post、delete方法,它们最终调用的都是sendRequest方法,如下:

 1 /**
 2      * Puts a new request in queue as a new thread in pool to be executed
 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 RequestHandle of future request process
12      */
13     protected RequestHandle sendRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest,
14             String contentType, ResponseHandlerInterface responseHandler, Context context) {
15         if (uriRequest == null) {
16             throw new IllegalArgumentException("HttpUriRequest must not be null");
17         }
18
19         if (responseHandler == null) {
20             throw new IllegalArgumentException("ResponseHandler must not be null");
21         }
22
23         if (responseHandler.getUseSynchronousMode()) {
24             throw new IllegalArgumentException("Synchronous ResponseHandler used in AsyncHttpClient. You should create your response handler in a looper thread or use SyncHttpClient instead.");
25         }
26
27         if (contentType != null) {
28             uriRequest.setHeader(HEADER_CONTENT_TYPE, contentType);
29         }
30
31         responseHandler.setRequestHeaders(uriRequest.getAllHeaders());
32         responseHandler.setRequestURI(uriRequest.getURI());
33         // 下面的这3行是重点,创建请求,提交请求到线程池,将请求包装到RequestHandle用于之后的取消、管理
34         AsyncHttpRequest request = newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context);
35         threadPool.submit(request); // 能submit说明request至少是个Runnable
36         RequestHandle requestHandle = new RequestHandle(request);
37
38         if (context != null) { // 如果Android context非空的话,做一些关联操作,后面可以通过context来取消request的执行
39             // Add request to request map
40             List<RequestHandle> requestList = requestMap.get(context);
41             synchronized (requestMap) {
42                 if (requestList == null) {
43                     requestList = Collections.synchronizedList(new LinkedList<RequestHandle>());
44                     requestMap.put(context, requestList);
45                 }
46             }
47
48             if (responseHandler instanceof RangeFileAsyncHttpResponseHandler)
49                 ((RangeFileAsyncHttpResponseHandler) responseHandler).updateRequestHeaders(uriRequest);
50
51             requestList.add(requestHandle);
52
53             Iterator<RequestHandle> iterator = requestList.iterator();
54             while (iterator.hasNext()) {
55                 if (iterator.next().shouldBeGarbageCollected()) {
56                     iterator.remove(); // 清理已经完成/取消了的请求
57                 }
58             }
59         }
60
61         return requestHandle;
62     }

看到了吧,发送请求的过程其实重点是创建请求,然后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的实现:

/**
 * 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代码如下:

 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(this, this.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端。

时间: 2024-10-21 23:36:38

android-async-http AsyncHttpClient的相关文章

看大师讲解Android快速开发框架EasyAndroid

前几天做了小应用,感觉小有成就,名字叫"长见识了",是一款趣味答题类的游戏,题目各种火爆各种经典,下载地址,看似一个简单的答题小游戏却是五脏俱全,从开发流程上都进行了严格的规范,大家有空可以下载玩玩~ 在这个应用中,用到了我以前集成的一个快速开发框架-EasyAndroid,这个框架我以前在做项目的时候总结,整理出来的,对于快速开发Android应用非常实用. 其实,Android应用的开发并不难,我们拿到一款Android应用后,百分之九十以上无外乎有这么几个功能: 1,IOC Mo

Android 通用流行框架大全

1. 缓存 DiskLruCache    Java实现基于LRU的磁盘缓存 2.图片加载 Android Universal Image Loader 一个强大的加载,缓存,展示图片的库 Picasso一个强大的图片下载与缓存的库 Fresco  一个用于管理图像和他们使用的内存的库 Glide   一个图片加载和缓存的库 3. 图片处理 Picasso-transformations 一个为Picasso提供多种图片变换的库 Glide-transformations   一个为Glide提

Android开发免费类库和工具集合

Android开发免费类库和工具集合 - OPEN 开发经验库 用于Android开发的免费类库和工具集合,按目录分类. Action Bars ActionBarSherlock Extended ActionBar FadingActionBar GlassActionBar v7 appcompat library 广告 AdMob Google Mobile Ads SDK InMobi mMedia mobileCore MoPub Tapjoy Analytics Google An

Android Volley 库的使用

本文内容 什么是 Volley 库 Volley 能做什么 Volley 架构 演示 Volley 库的使用 参考资料 Android 关于网络操作一般都会介绍 HttpClient 以及 HttpConnection 这两个包.前者是 Apache 开源库,后者是 Android 自带 API.企业级应用,一般都会选择使用已经封装好的 http 框架.比较流行有 Volley.android-async-http.retrofit.okhttp.androidquery.AndroidAsyn

Android通用流行框架大全

1. 缓存 名称 描述 DiskLruCache Java实现基于LRU的磁盘缓存 2.图片加载 名称 描述 Android Universal Image Loader 一个强大的加载,缓存,展示图片的库 Picasso 一个强大的图片下载与缓存的库 Fresco 一个用于管理图像和他们使用的内存的库 Glide 一个图片加载和缓存的库 3. 图片处理 名称 描述 Picasso-transformations 一个为Picasso提供多种图片变换的库 Glide-transformation

15 个 Android 通用流行框架大全

1. 缓存 名称 描述 DiskLruCache Java实现基于LRU的磁盘缓存 2.图片加载 名称 描述 Android Universal Image Loader 一个强大的加载,缓存,展示图片的库 Picasso 一个强大的图片下载与缓存的库 Fresco 一个用于管理图像和他们使用的内存的库 Glide 一个图片加载和缓存的库 3. 图片处理 名称 描述 Picasso-transformations 一个为Picasso提供多种图片变换的库 Glide-transformation

经受时间沉淀的15 个 Android 通用流行框架大全

1. 缓存 名称描述 DiskLruCache: Java实现基于LRU的磁盘缓存 2.图片加载 名称描述 Android    Universal Image Loader 一个强大的加载,缓存,展示图片的库 Picasso    一个强大的图片下载与缓存的库 Fresco    一个用于管理图像和他们使用的内存的库 Glide    一个图片加载和缓存的库 公众号:JANiubility 3. 图片处理 名称描述 Picasso-transformations    一个为 Picasso

Android通用流行框架汇总

概述 1. 缓存 名称 名称 DiskLruCache Java实现基于LRU的磁盘缓存 2.图片加载 名称 描述 Android Universal Image Loader 一个强大的加载,缓存,展示图片的库 Picasso 一个强大的图片下载与缓存的库 Fresco 一个用于管理图像和他们使用的内存的库 Glide 一个图片加载和缓存的库 3. 图片处理 名称 描述 Picasso-transformations 一个为Picasso提供多种图片变换的库 Glide-transformat

Android常用库

原文链接:http://www.jianshu.com/p/19368c2cdcaf 系统框架 1. 网络请求 Android Async HTTP Android异步HTTP库 AndroidAsync 异步Socket,HTTP(客户端+服务器),WebSocket,和socket.io库.基于NIO而不是线程. Okhttp Http与Http/2的客户端 Retrofit okhttp再封装 Volley Google推出的Android异步网络请求框架和图片加载框架 2. 网络解析 G

60.Android通用流行框架大全

转载:https://segmentfault.com/a/1190000005073746 Android通用流行框架大全 1. 缓存 名称 描述 DiskLruCache Java实现基于LRU的磁盘缓存 2.图片加载 名称 描述 Android Universal Image Loader 一个强大的加载,缓存,展示图片的库 Picasso 一个强大的图片下载与缓存的库 Fresco 一个用于管理图像和他们使用的内存的库 Glide 一个图片加载和缓存的库 3. 图片处理 名称 描述 Pi