码迷,mamicode.com
首页 > 移动开发 > 详细

android-async-http AsyncHttpClient

时间:2015-06-05 06:12:45      阅读:1939      评论:0      收藏:0      [点我收藏+]

标签:

它是专门针对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端。

android-async-http AsyncHttpClient

标签:

原文地址:http://www.cnblogs.com/code4mobile/p/4553549.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!