AsyncHttpClient 源码分析_headers were overwritten-程序员宅基地

技术标签: AsyncHttpClient源码  AsyncHttpClient源码分析  android  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。。。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/codepython/article/details/46333523

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法