AsyncHttpClient 源码分析

来源:互联网 发布:手机淘宝忘记密码 编辑:程序博客网 时间:2024/05/22 04:33

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

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

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

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

1. AsyncHttpClient自己一个模块;

2. AsyncHttpRequest和RequestHandler一个模块;

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

4. RetryHandler,自动重试机制。

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

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

复制代码
    public static final String LOG_TAG = "AsyncHttpClient";    public static final String HEADER_CONTENT_TYPE = "Content-Type";    public static final String HEADER_CONTENT_RANGE = "Content-Range";    public static final String HEADER_CONTENT_ENCODING = "Content-Encoding";    public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition";    public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";    public static final String ENCODING_GZIP = "gzip";    public static final int DEFAULT_MAX_CONNECTIONS = 10;    public static final int DEFAULT_SOCKET_TIMEOUT = 10 * 1000;    public static final int DEFAULT_MAX_RETRIES = 5;    public static final int DEFAULT_RETRY_SLEEP_TIME_MILLIS = 1500;    public static final int DEFAULT_SOCKET_BUFFER_SIZE = 8192;    private int maxConnections = DEFAULT_MAX_CONNECTIONS;    private int connectTimeout = DEFAULT_SOCKET_TIMEOUT;    private int responseTimeout = DEFAULT_SOCKET_TIMEOUT; // 各种参数设置    private final DefaultHttpClient httpClient; // 包装的Apache 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端。

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

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

原创粉丝点击