• android-async-http AsyncHttpClient介绍


      在Android开发中,发送、处理http请求简直太常见了,以至于我们的代码里到处充斥着各种HttpClient和与之相关又臭又长的代码,

    它们存在于你代码的各个角落,每次看见都令人作呕,而你仅仅是为了server能返回一个string或者json给你。每次当我自己写这样

    的代码时,我都会想能不能简化下这个流程,可能2、3行代码就能搞定。因为针对最简单的case,我只需要提供request url,成功时的

    callback和(或)失败时的callback,仅此而已。针对这一类问题(需求),可以说android-async-http提供了几乎完美的解决方案。

    通过使用它可以大大简化你的代码,不仅如此,你的代码看上去也优雅多了。

      当我第一眼看到它时就被吸引住了,特别是async关键字,干我们这行的都知道,这是异步执行,也就是说它的网络请求自动在非UI

    线程里执行,你不需要任何额外的操作(比如手动new一个Thread之类)。项目的官方网站:

    http://loopj.com/android-async-http/,对应的github地址:https://github.com/loopj/android-async-http

      我这里简要介绍下:它是专门针对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。

    大概翻译了下,这些只是大体的概览,具体的细节还得在使用过程中慢慢感受、学习。

      接下来,带领大家看看应用android-async-http来写代码是个啥样子。简单来说你只需要3步,

    1. 创建一个AsyncHttpClient;

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

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

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

    来看看代码如何写:

    复制代码
    AsyncHttpClient client = new AsyncHttpClient();
    client.get("http://www.google.com", new AsyncHttpResponseHandler() {
    
        @Override
        public void onStart() {
            // called before request is started
        }
    
        @Override
        public void onSuccess(int statusCode, Header[] headers, byte[] response) {
            // called when response HTTP status is "200 OK"
        }
    
        @Override
        public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
            // called when response HTTP status is "4XX" (eg. 401, 403, 404)
        }
    
        @Override
        public void onRetry(int retryNo) {
            // called when request is retried
        }
    });
    复制代码

    是不是很简洁,有没有被震撼到?反正我自己第一次看到的时候有种相见恨晚的感觉,这简直就是我日思夜想的方式啊!这里你只需要通过

    匿名内部类的方式实现AsyncHttpResponseHandler,而且更棒的是你只需要override感兴趣的方法,比如一般都是onSuccess和onFailure。

    这个版本的get方法没有为请求传递任何参数,当然你也可以通过RequestParams来传递各种参数,如下:

    复制代码
    AsyncHttpClient client = new AsyncHttpClient();
    RequestParams params = new RequestParams();
    params.put("key", "value");
    params.put("more", "data");
    client.get("http://www.google.com", params, new
        AsyncHttpResponseHandler() {
            @Override
            public void onSuccess(int statusCode, Header[] headers, byte[] response) {
                System.out.println(response);
            }
    
            @Override
            public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
                Log.d("ERROR", error);
            }    
        }
    );
    复制代码

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

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

    代码如下:

    复制代码
    AsyncHttpClient client = new AsyncHttpClient();
    RequestParams params = new RequestParams();
    params.put("key", "value");
    params.put("more", "data");
    client.get("http://www.google.com", params, new
        TextHttpResponseHandler() {
            @Override
            public void onSuccess(int statusCode, Header[] headers, String response) {
                System.out.println(response);
            }
    
            @Override
            public void onFailure(int statusCode, Header[] headers, String responseBody, Throwable error) {
                Log.d("ERROR", error);
            }    
        }
    );
    复制代码

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

    复制代码
    String url = "https://ajax.googleapis.com/ajax/services/search/images";
    AsyncHttpClient client = new AsyncHttpClient();
    RequestParams params = new RequestParams();
    params.put("q", "android");
    params.put("rsz", "8");
    client.get(url, params, new JsonHttpResponseHandler() {            
        @Override
        public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
           // Handle resulting parsed JSON response here
        }
        @Override
        public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
          // Handle resulting parsed JSON response here
        }
    });
    复制代码

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

      有了AsyncHttpClient,要实现这些功能是不是很简单呢?当然这里只是很初级的介绍和使用,剩下的还需要开发者自己参考官方

    文档、源码(官方甚至提供了一个Sample使用的集合),在实际项目中实践。最后,强烈建议大家使用,是时候和冗长乏味的代码说

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

    1. AsyncHttpClient自己一个模块;

    2. AsyncHttpRequest和RequestHandler一个模块;

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

    4. RetryHandler,自动重试机制。

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

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

    复制代码
        public static final String LOG_TAG = "AsyncHttpClient";
    
        public static final String HEADER_CONTENT_TYPE = "Content-Type";
        public static final String HEADER_CONTENT_RANGE = "Content-Range";
        public static final String HEADER_CONTENT_ENCODING = "Content-Encoding";
        public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition";
        public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
        public static final String ENCODING_GZIP = "gzip";
    
        public static final int DEFAULT_MAX_CONNECTIONS = 10;
        public static final int DEFAULT_SOCKET_TIMEOUT = 10 * 1000;
        public static final int DEFAULT_MAX_RETRIES = 5;
        public static final int DEFAULT_RETRY_SLEEP_TIME_MILLIS = 1500;
        public static final int DEFAULT_SOCKET_BUFFER_SIZE = 8192;
    
        private int maxConnections = DEFAULT_MAX_CONNECTIONS;
        private int connectTimeout = DEFAULT_SOCKET_TIMEOUT;
        private int responseTimeout = DEFAULT_SOCKET_TIMEOUT; // 各种参数设置
    
        private final DefaultHttpClient httpClient; // 包装的Apache DefaultHttpClient
        private final HttpContext httpContext;
        private ExecutorService threadPool; // 执行网络请求的线程池
        private final Map<Context, List<RequestHandle>> requestMap; // 与Android Context对应的请求map
        private final Map<String, String> clientHeaderMap; // 客户端的请求header map
        private boolean isUrlEncodingEnabled = true; // 允许url encoding
    复制代码

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

    复制代码
        /**
         * Creates a new AsyncHttpClient with default constructor arguments values
         */
        public AsyncHttpClient() { // 一般客户端代码中都直接调用这个版本的ctor
            this(false, 80, 443);
        }
    
        /**
         * Creates a new AsyncHttpClient.
         *
         * @param httpPort non-standard HTTP-only port
         */
        public AsyncHttpClient(int httpPort) {
            this(false, httpPort, 443);
        }
    
        /**
         * Creates a new AsyncHttpClient.
         *
         * @param httpPort  non-standard HTTP-only port
         * @param httpsPort non-standard HTTPS-only port
         */
        public AsyncHttpClient(int httpPort, int httpsPort) {
            this(false, httpPort, httpsPort);
        }
    
        /**
         * Creates new AsyncHttpClient using given params
         *
         * @param fixNoHttpResponseException Whether to fix or not issue, by omitting SSL verification
         * @param httpPort                   HTTP port to be used, must be greater than 0
         * @param httpsPort                  HTTPS port to be used, must be greater than 0
         */
        public AsyncHttpClient(boolean fixNoHttpResponseException, int httpPort, int httpsPort) {
            this(getDefaultSchemeRegistry(fixNoHttpResponseException, httpPort, httpsPort));
        }
    
        /**
         * Returns default instance of SchemeRegistry
         *
         * @param fixNoHttpResponseException Whether to fix or not issue, by omitting SSL verification
         * @param httpPort                   HTTP port to be used, must be greater than 0
         * @param httpsPort                  HTTPS port to be used, must be greater than 0
         */
        private static SchemeRegistry getDefaultSchemeRegistry(boolean fixNoHttpResponseException, int httpPort, int httpsPort) {
            if (fixNoHttpResponseException) { // 如果你请求的url是https的,并且遇到了SSL验证之类的错误,那么你应该将此值设为true试试
                Log.d(LOG_TAG, "Beware! Using the fix is insecure, as it doesn't verify SSL certificates.");
            }
    
            if (httpPort < 1) {
                httpPort = 80;
                Log.d(LOG_TAG, "Invalid HTTP port number specified, defaulting to 80");
            }
    
            if (httpsPort < 1) {
                httpsPort = 443;
                Log.d(LOG_TAG, "Invalid HTTPS port number specified, defaulting to 443");
            }
    
            // Fix to SSL flaw in API < ICS
            // See https://code.google.com/p/android/issues/detail?id=13117
            SSLSocketFactory sslSocketFactory;
            if (fixNoHttpResponseException) { // 感兴趣的同学可自行看看MySSLSocketFactory的实现,基本上是省略了SSL验证环节
                sslSocketFactory = MySSLSocketFactory.getFixedSocketFactory();
            } else {
                sslSocketFactory = SSLSocketFactory.getSocketFactory();
            }
    
            SchemeRegistry schemeRegistry = new SchemeRegistry();
            schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), httpPort));
            schemeRegistry.register(new Scheme("https", sslSocketFactory, httpsPort));
    
            return schemeRegistry;
        }
    
        /**
         * Creates a new AsyncHttpClient.
         *
         * @param schemeRegistry SchemeRegistry to be used
         */
        public AsyncHttpClient(SchemeRegistry schemeRegistry) { // 最终调到的是这个版本。。。
    
            BasicHttpParams httpParams = new BasicHttpParams();
            // 接下来是设置各种参数。。。
            ConnManagerParams.setTimeout(httpParams, connectTimeout);
            ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(maxConnections));
            ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS);
    
            HttpConnectionParams.setSoTimeout(httpParams, responseTimeout);
            HttpConnectionParams.setConnectionTimeout(httpParams, connectTimeout);
            HttpConnectionParams.setTcpNoDelay(httpParams, true);
            HttpConnectionParams.setSocketBufferSize(httpParams, DEFAULT_SOCKET_BUFFER_SIZE);
            
            HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
    
            ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(httpParams, schemeRegistry);
            // 初始化关键字段
            threadPool = getDefaultThreadPool();
            requestMap = Collections.synchronizedMap(new WeakHashMap<Context, List<RequestHandle>>());
            clientHeaderMap = new HashMap<String, String>();
    
            httpContext = new SyncBasicHttpContext(new BasicHttpContext());
            httpClient = new DefaultHttpClient(cm, httpParams);
            httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
                @Override
                public void process(HttpRequest request, HttpContext context) {
                    if (!request.containsHeader(HEADER_ACCEPT_ENCODING)) {
                        request.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
                    }
                    for (String header : clientHeaderMap.keySet()) {
                        if (request.containsHeader(header)) {
                            Header overwritten = request.getFirstHeader(header);
                            Log.d(LOG_TAG,
                                    String.format("Headers were overwritten! (%s | %s) overwrites (%s | %s)",
                                            header, clientHeaderMap.get(header),
                                            overwritten.getName(), overwritten.getValue())
                            );
    
                            //remove the overwritten header
                            request.removeHeader(overwritten);
                        }
                        request.addHeader(header, clientHeaderMap.get(header));
                    }
                }
            });
    
            httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
                @Override
                public void process(HttpResponse response, HttpContext context) {
                    final HttpEntity entity = response.getEntity();
                    if (entity == null) {
                        return;
                    }
                    final Header encoding = entity.getContentEncoding();
                    if (encoding != null) {
                        for (HeaderElement element : encoding.getElements()) {
                            if (element.getName().equalsIgnoreCase(ENCODING_GZIP)) {
                                response.setEntity(new InflatingEntity(entity));
                                break;
                            }
                        }
                    }
                }
            });
    
            httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
                @Override
                public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
                    AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
                    CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(
                            ClientContext.CREDS_PROVIDER);
                    HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
    
                    if (authState.getAuthScheme() == null) {
                        AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort());
                        Credentials creds = credsProvider.getCredentials(authScope);
                        if (creds != null) {
                            authState.setAuthScheme(new BasicScheme());
                            authState.setCredentials(creds);
                        }
                    }
                }
            }, 0);
            // 设置重试Handler,会在合适的情况下自动重试
            httpClient.setHttpRequestRetryHandler(new RetryHandler(DEFAULT_MAX_RETRIES, DEFAULT_RETRY_SLEEP_TIME_MILLIS));
        }
    复制代码

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

    复制代码
        /**
         * Puts a new request in queue as a new thread in pool to be executed
         *
         * @param client          HttpClient to be used for request, can differ in single requests
         * @param contentType     MIME body type, for POST and PUT requests, may be null
         * @param context         Context of Android application, to hold the reference of request
         * @param httpContext     HttpContext in which the request will be executed
         * @param responseHandler ResponseHandler or its subclass to put the response into
         * @param uriRequest      instance of HttpUriRequest, which means it must be of HttpDelete,
         *                        HttpPost, HttpGet, HttpPut, etc.
         * @return RequestHandle of future request process
         */
        protected RequestHandle sendRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest,
                String contentType, ResponseHandlerInterface responseHandler, Context context) {
            if (uriRequest == null) {
                throw new IllegalArgumentException("HttpUriRequest must not be null");
            }
    
            if (responseHandler == null) {
                throw new IllegalArgumentException("ResponseHandler must not be null");
            }
    
            if (responseHandler.getUseSynchronousMode()) {
                throw new IllegalArgumentException("Synchronous ResponseHandler used in AsyncHttpClient. You should create your response handler in a looper thread or use SyncHttpClient instead.");
            }
    
            if (contentType != null) {
                uriRequest.setHeader(HEADER_CONTENT_TYPE, contentType);
            }
    
            responseHandler.setRequestHeaders(uriRequest.getAllHeaders());
            responseHandler.setRequestURI(uriRequest.getURI());
            // 下面的这3行是重点,创建请求,提交请求到线程池,将请求包装到RequestHandle用于之后的取消、管理
            AsyncHttpRequest request = newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context);
            threadPool.submit(request); // 能submit说明request至少是个Runnable
            RequestHandle requestHandle = new RequestHandle(request);
    
            if (context != null) { // 如果Android context非空的话,做一些关联操作,后面可以通过context来取消request的执行
                // Add request to request map
                List<RequestHandle> requestList = requestMap.get(context);
                synchronized (requestMap) {
                    if (requestList == null) {
                        requestList = Collections.synchronizedList(new LinkedList<RequestHandle>());
                        requestMap.put(context, requestList);
                    }
                }
    
                if (responseHandler instanceof RangeFileAsyncHttpResponseHandler)
                    ((RangeFileAsyncHttpResponseHandler) responseHandler).updateRequestHeaders(uriRequest);
    
                requestList.add(requestHandle);
    
                Iterator<RequestHandle> iterator = requestList.iterator();
                while (iterator.hasNext()) {
                    if (iterator.next().shouldBeGarbageCollected()) {
                        iterator.remove(); // 清理已经完成/取消了的请求
                    }
                }
            }
    
            return requestHandle;
        }
    复制代码

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

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

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

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

    复制代码
    /**
     * Internal class, representing the HttpRequest, done in asynchronous manner
     */
    public class AsyncHttpRequest implements Runnable { // 这就是submit到线程池的Runnable
        private final AbstractHttpClient client;
        private final HttpContext context;
        private final HttpUriRequest request;
        private final ResponseHandlerInterface responseHandler;
        private int executionCount;
        private boolean isCancelled;
        private boolean cancelIsNotified;
        private boolean isFinished;
        private boolean isRequestPreProcessed;
    
        public AsyncHttpRequest(AbstractHttpClient client, HttpContext context, HttpUriRequest request, ResponseHandlerInterface responseHandler) {
            this.client = client;
            this.context = context;
            this.request = request;
            this.responseHandler = responseHandler;
        }
    
        /**
         * This method is called once by the system when the request is about to be
         * processed by the system. The library makes sure that a single request
         * is pre-processed only once.
         *
         * Please note: pre-processing does NOT run on the main thread, and thus
         * any UI activities that you must perform should be properly dispatched to
         * the app's UI thread.
         *
         * @param request The request to pre-process
         */
        public void onPreProcessRequest(AsyncHttpRequest request) {
            // default action is to do nothing...
        }
    
        /**
         * This method is called once by the system when the request has been fully
         * sent, handled and finished. The library makes sure that a single request
         * is post-processed only once.
         *
         * Please note: post-processing does NOT run on the main thread, and thus
         * any UI activities that you must perform should be properly dispatched to
         * the app's UI thread.
         *
         * @param request The request to post-process
         */
        public void onPostProcessRequest(AsyncHttpRequest request) {
            // default action is to do nothing...
        }
    
        @Override
        public void run() { // 这是在线程池中执行的方法,我们重点看看
            if (isCancelled()) { // 检测,如果已经取消了则直接返回,下面的代码有好多次做这个检测,因为你永远不知道什么时候会被取消
                return;          // 同时也说明了我们的Request是支持取消的
            }
    
            // Carry out pre-processing for this request only once.
            if (!isRequestPreProcessed) {
                isRequestPreProcessed = true;
                onPreProcessRequest(this); // callback接口,在一次请求中只调用一次
            }
    
            if (isCancelled()) { // 再次检查
                return;
            }
    
            if (responseHandler != null) {
                responseHandler.sendStartMessage(); // 发送开始请求消息
            }
    
            if (isCancelled()) { // 检查
                return;
            }
    
            try {
                makeRequestWithRetries(); // 带自动retry机制的请求
            } catch (IOException e) {
                if (!isCancelled() && responseHandler != null) {
                    responseHandler.sendFailureMessage(0, null, null, e); // 在没取消的情况下,发送失败消息
                } else {
                    Log.e("AsyncHttpRequest", "makeRequestWithRetries returned error, but handler is null", e);
                }
            }
    
            if (isCancelled()) { // 检查again
                return;
            }
    
            if (responseHandler != null) { // 没取消的情况下,发送完成消息
                responseHandler.sendFinishMessage();
            }
    
            if (isCancelled()) {
                return;
            }
    
            // Carry out post-processing for this request.
            onPostProcessRequest(this); // 处理了请求之后的callback
    
            isFinished = true; // 设置为true表示这个请求执行完毕了
        }
    
        private void makeRequest() throws IOException { // 发送一次请求
            if (isCancelled()) {
                return;
            }
    
            // Fixes #115
            if (request.getURI().getScheme() == null) {
                // subclass of IOException so processed in the caller
                throw new MalformedURLException("No valid URI scheme was provided");
            }
            // 执行请求获得response
            HttpResponse response = client.execute(request, context);
    
            if (isCancelled() || responseHandler == null) {
                return;
            }
    
            // Carry out pre-processing for this response.
            responseHandler.onPreProcessResponse(responseHandler, response); // 处理response前
    
            if (isCancelled()) {
                return;
            }
    
            // The response is ready, handle it.
            responseHandler.sendResponseMessage(response); // 发送获得的response
    
            if (isCancelled()) {
                return;
            }
    
            // Carry out post-processing for this response.
            responseHandler.onPostProcessResponse(responseHandler, response); // 处理response后
        }
    
        private void makeRequestWithRetries() throws IOException {
            boolean retry = true;
            IOException cause = null;
            HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler();
            try {
                while (retry) { // 注意这个循环,当retry为false的时候退出
                    try {
                        makeRequest();
                        return; // 请求成功的话,直接返回
                    } catch (UnknownHostException e) {
                        // switching between WI-FI and mobile data networks can cause a retry which then results in an UnknownHostException
                        // while the WI-FI is initialising. The retry logic will be invoked here, if this is NOT the first retry
                        // (to assist in genuine cases of unknown host) which seems better than outright failure
                        cause = new IOException("UnknownHostException exception: " + e.getMessage());
                        retry = (executionCount > 0) && retryHandler.retryRequest(cause, ++executionCount, context);
                    } catch (NullPointerException e) {
                        // there's a bug in HttpClient 4.0.x that on some occasions causes
                        // DefaultRequestExecutor to throw an NPE, see
                        // http://code.google.com/p/android/issues/detail?id=5255
                        cause = new IOException("NPE in HttpClient: " + e.getMessage());
                        retry = retryHandler.retryRequest(cause, ++executionCount, context);
                    } catch (IOException e) {
                        if (isCancelled()) {
                            // Eating exception, as the request was cancelled
                            return;
                        }
                        cause = e;
                        retry = retryHandler.retryRequest(cause, ++executionCount, context);
                    }
    // 各种异常的情况下,计算retry,看还是否需要retry if (retry && (responseHandler != null)) { // 需要retry的时候,发送retry消息并附带第几次retry了 responseHandler.sendRetryMessage(executionCount); } } } catch (Exception e) { // catch anything else to ensure failure message is propagated Log.e("AsyncHttpRequest", "Unhandled exception origin cause", e);
    // 其他的所有不在上述catch里的异常都在这里统一包装成IOException,在最后抛出 cause = new IOException("Unhandled exception: " + e.getMessage()); } // cleaned up to throw IOException throw (cause); // 抛出,以便上层代码知道发生了什么 } public boolean isCancelled() { if (isCancelled) { sendCancelNotification(); } return isCancelled; } private synchronized void sendCancelNotification() { if (!isFinished && isCancelled && !cancelIsNotified) { cancelIsNotified = true; if (responseHandler != null) responseHandler.sendCancelMessage(); } } public boolean isDone() { return isCancelled() || isFinished; } public boolean cancel(boolean mayInterruptIfRunning) { isCancelled = true; request.abort(); return isCancelled(); } }
    复制代码

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

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

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

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

    复制代码
        /**
         * Creates a new AsyncHttpResponseHandler
         */
        public AsyncHttpResponseHandler() { // 不指定looper
            this(null);
        }
    
        /**
         * Creates a new AsyncHttpResponseHandler with a user-supplied looper. If
         * the passed looper is null, the looper attached to the current thread will
         * be used.
         *
         * @param looper The looper to work with
         */
        public AsyncHttpResponseHandler(Looper looper) { // 如果没指定looper的话,会用当前线程的looper顶替
            this.looper = looper == null ? Looper.myLooper() : looper;
            // Use asynchronous mode by default.
            setUseSynchronousMode(false); // 默认是异步的方式,这里异步的意思是指对response的处理发生在与looper
        }                                 // 关联的线程中,而不是请求发生的线程池里的线程中
    
        @Override
        public void setUseSynchronousMode(boolean sync) {
            // A looper must be prepared before setting asynchronous mode.
            if (!sync && this.looper == null) {
                sync = true; // 一种错误的情况,强制使用同步mode
                Log.w(LOG_TAG, "Current thread has not called Looper.prepare(). Forcing synchronous mode.");
            }
    
            // If using asynchronous mode.
            if (!sync && handler == null) { // 初始化handler
                // Create a handler on current thread to submit tasks
                handler = new ResponderHandler(this, this.looper);
            } else if (sync && handler != null) {
                // TODO: Consider adding a flag to remove all queued messages.
                handler = null;
            }
    
            useSynchronousMode = sync;
        }
    复制代码

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

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

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

    复制代码
        /**
         * Avoid leaks by using a non-anonymous handler class.
         */
        private static class ResponderHandler extends Handler {
            private final AsyncHttpResponseHandler mResponder;
    
            ResponderHandler(AsyncHttpResponseHandler mResponder, Looper looper) {
                super(looper);
                this.mResponder = mResponder;
            }
    
            @Override
            public void handleMessage(Message msg) { // 一个简单的Handler,其handleMessage delegate给了mResponder
                mResponder.handleMessage(msg);
            }
        }
    
        // Methods which emulate android's Handler and Message methods
        protected void handleMessage(Message message) { // 对各种message的处理,回调各种onXXX方法
            Object[] response;
    
            switch (message.what) {
                case SUCCESS_MESSAGE:
                    response = (Object[]) message.obj;
                    if (response != null && response.length >= 3) {
                        onSuccess((Integer) response[0], (Header[]) response[1], (byte[]) response[2]);
                    } else {
                        Log.e(LOG_TAG, "SUCCESS_MESSAGE didn't got enough params");
                    }
                    break;
                case FAILURE_MESSAGE:
                    response = (Object[]) message.obj;
                    if (response != null && response.length >= 4) {
                        onFailure((Integer) response[0], (Header[]) response[1], (byte[]) response[2], (Throwable) response[3]);
                    } else {
                        Log.e(LOG_TAG, "FAILURE_MESSAGE didn't got enough params");
                    }
                    break;
                case START_MESSAGE:
                    onStart();
                    break;
                case FINISH_MESSAGE:
                    onFinish();
                    break;
                case PROGRESS_MESSAGE:
                    response = (Object[]) message.obj;
                    if (response != null && response.length >= 2) {
                        try {
                            onProgress((Integer) response[0], (Integer) response[1]);
                        } catch (Throwable t) {
                            Log.e(LOG_TAG, "custom onProgress contains an error", t);
                        }
                    } else {
                        Log.e(LOG_TAG, "PROGRESS_MESSAGE didn't got enough params");
                    }
                    break;
                case RETRY_MESSAGE:
                    response = (Object[]) message.obj;
                    if (response != null && response.length == 1) {
                        onRetry((Integer) response[0]);
                    } else {
                        Log.e(LOG_TAG, "RETRY_MESSAGE didn't get enough params");
                    }
                    break;
                case CANCEL_MESSAGE:
                    onCancel();
                    break;
            }
        }
    
        protected void sendMessage(Message msg) {
            if (getUseSynchronousMode() || handler == null) {
                handleMessage(msg); // 如果是同步的方式,则handleMessage发生在调用sendMessage的线程中
            } else if (!Thread.currentThread().isInterrupted()) { // do not send messages if request has been cancelled
                handler.sendMessage(msg); // 否则发生在与handler关联的线程中,一般多为UI线程
            }
        }
    复制代码

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

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

    复制代码
        @Override
        public void sendResponseMessage(HttpResponse response) throws IOException {
            // do not process if request has been cancelled
            if (!Thread.currentThread().isInterrupted()) {
                StatusLine status = response.getStatusLine();
                byte[] responseBody;
                responseBody = getResponseData(response.getEntity()); // 将response解析成字节数组
                // additional cancellation check as getResponseData() can take non-zero time to process
                if (!Thread.currentThread().isInterrupted()) {
                    if (status.getStatusCode() >= 300) { // 标志失败的情况
                        sendFailureMessage(status.getStatusCode(), response.getAllHeaders(), responseBody, new HttpResponseException(status.getStatusCode(), status.getReasonPhrase()));
                    } else { // 成功的情况
                        sendSuccessMessage(status.getStatusCode(), response.getAllHeaders(), responseBody);
                    }
                }
            }
        }
    
        /**
         * Returns byte array of response HttpEntity contents
         *
         * @param entity can be null
         * @return response entity body or null
         * @throws java.io.IOException if reading entity or creating byte array failed
         */
        byte[] getResponseData(HttpEntity entity) throws IOException {
            byte[] responseBody = null;
            if (entity != null) {
                InputStream instream = entity.getContent(); // 从entity中读取字节流
                if (instream != null) {
                    long contentLength = entity.getContentLength();
                    if (contentLength > Integer.MAX_VALUE) {
                        throw new IllegalArgumentException("HTTP entity too large to be buffered in memory");
                    }
                    int buffersize = (contentLength <= 0) ? BUFFER_SIZE : (int) contentLength;
                    try {
                        ByteArrayBuffer buffer = new ByteArrayBuffer(buffersize);
                        try {
                            byte[] tmp = new byte[BUFFER_SIZE];
                            int l, count = 0;
                            // do not send messages if request has been cancelled
                            while ((l = instream.read(tmp)) != -1 && !Thread.currentThread().isInterrupted()) {
                                count += l;
                                buffer.append(tmp, 0, l);
                                sendProgressMessage(count, (int) (contentLength <= 0 ? 1 : contentLength));
                            }
                        } finally {
                            AsyncHttpClient.silentCloseInputStream(instream);
                            AsyncHttpClient.endEntityViaReflection(entity);
                        }
                        responseBody = buffer.toByteArray();
                    } catch (OutOfMemoryError e) {
                        System.gc();
                        throw new IOException("File too large to fit into available memory");
                    }
                }
            }
            return responseBody;
        }
    复制代码

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

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

    复制代码
        @Override // 对上述2个方法的重载,其中将byte[]通过getResponseString方法转化成了String对象
        public void onSuccess(int statusCode, Header[] headers, byte[] responseBytes) {
            onSuccess(statusCode, headers, getResponseString(responseBytes, getCharset()));
        }
    
        @Override
        public void onFailure(int statusCode, Header[] headers, byte[] responseBytes, Throwable throwable) {
            onFailure(statusCode, headers, getResponseString(responseBytes, getCharset()), throwable);
        }
    
        /**
         * Attempts to encode response bytes as string of set encoding
         *
         * @param charset     charset to create string with
         * @param stringBytes response bytes
         * @return String of set encoding or null
         */
        public static String getResponseString(byte[] stringBytes, String charset) {
            try {
                String toReturn = (stringBytes == null) ? null : new String(stringBytes, charset);
                if (toReturn != null && toReturn.startsWith(UTF8_BOM)) {
                    return toReturn.substring(1);
                }
                return toReturn;
            } catch (UnsupportedEncodingException e) {
                Log.e(LOG_TAG, "Encoding response into string failed", e);
                return null;
            }
        }
    复制代码

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

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

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

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

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

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

  • 相关阅读:
    RPC学习
    json
    jsf
    ajax分析
    async分析
    web后台
    servlet和CGI区别(转)
    forward和redirect
    (转)jvm
    Async分析
  • 原文地址:https://www.cnblogs.com/shanzei/p/4647682.html
Copyright © 2020-2023  润新知