Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android-async-http框架源碼詳解

android-async-http框架源碼詳解

編輯:關於Android編程

async-http使用地址

android-async-http倉庫:git clonehttps://github.com/loopj/android-async-http

源碼分析

我們在做網絡請求的時候經常通過下面的方式實例化AsyncHttpClient client=new AsyncHttpClient();然後通過系統內置的請求發送請求,通過async內部的請求去做真正的網絡請求。

 

首先得到的是AsyncHttpClient實例,所以從這裡入手分析一下:

    /**
     * Creates a new AsyncHttpClient with default constructor arguments values
     */
    public AsyncHttpClient() {
        this(false, 80, 443);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

對於默認值設置了HTTP協議的默認端口為80,HTTPS協議的默認端口為443。

 

在該函數中調用了AsyncHttpClient(SchemeRegistry schemeRegistry)構造函數,而真正的實例化獲取邏輯過程就在AsyncHttpClient(SchemeRegistry 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);

    ClientConnectionManager cm = createConnectionManager(schemeRegistry, httpParams);
    Utils.asserts(cm != null, "Custom implementation of #createConnectionManager(SchemeRegistry, BasicHttpParams) returned null");

    threadPool = getDefaultThreadPool();
    requestMap = Collections.synchronizedMap(new WeakHashMap>());
    clientHeaderMap = new HashMap();

    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);

    httpClient.setHttpRequestRetryHandler(new RetryHandler(DEFAULT_MAX_RETRIES, DEFAULT_RETRY_SLEEP_TIME_MILLIS));
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92

從代碼的最頂層分析,構造參數傳入的是SchemeRegistry對象,查看源碼這是一個靜態的方法,主要存儲一些協議的東西

public SchemeRegistry() {
super();
registeredSchemes = new ConcurrentHashMap();
}

上面的代碼我們主要關注下addResponseInterceptor和addResponseInterceptor,此兩個方法主要將我們的請求頭和請求的實體加到HttpRequest隊列中,對android1.5之前的熟悉的朋友都知道,在最早之前沒有流行這些第三方之前我們就是通過HttpRequest來請求的,這等同於j2ee的HttpServletRequest.

 

接下來我們調運的就是AsyncHttpClient裡面的各種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() && !responseHandler.getUsePoolThread()) {
            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) {
            if (uriRequest instanceof HttpEntityEnclosingRequestBase && ((HttpEntityEnclosingRequestBase) uriRequest).getEntity() != null) {
                Log.w(LOG_TAG, "Passed contentType will be ignored because HttpEntity sets content type");
            } else {
                uriRequest.setHeader(HEADER_CONTENT_TYPE, contentType);
            }
        }

        responseHandler.setRequestHeaders(uriRequest.getAllHeaders());
        responseHandler.setRequestURI(uriRequest.getURI());

        AsyncHttpRequest request = newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context);
        threadPool.submit(request);
        RequestHandle requestHandle = new RequestHandle(request);

        if (context != null) {
            // Add request to request map
            List requestList = requestMap.get(context);
            synchronized (requestMap) {
                if (requestList == null) {
                    requestList = Collections.synchronizedList(new LinkedList());
                    requestMap.put(context, requestList);
                }
            }

            requestList.add(requestHandle);

            Iterator iterator = requestList.iterator();
            while (iterator.hasNext()) {
                if (iterator.next().shouldBeGarbageCollected()) {
                    iterator.remove();
                }
            }
        }

        return requestHandle;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

這個方法的主要作用是將一個新的請求添加到隊列線程池中執行。

調用本方法,主要實現AsyncHttpRequest request = newAsyncHttpRequest(client, httpContext, uriRequest,contentType, responseHandler, context);這行開始是主要的邏輯,其創建了請求,接著通過threadPool.submit(request);把請求提交到線程池,接著通過RequestHandle requestHandle = new RequestHandle(request);把請求包裝到RequestHandle用於之後的取消、管理等操作。然後坐等現在池的我們請求的這個線程去執行,等待返回結果。

總結一下:

 

AsyncHttpClient 核心類,使用HttpClient執行網絡請求,提供了get,put,post,delete,head等請求方法,使用起來很簡單,只需以url及RequestParams調用相應的方法即可,還可以選擇性地傳入Context,用於取消Content相關的請求,同時必須提供ResponseHandlerInterface(AsyncHttpResponseHandler繼承自ResponseHandlerInterface)的實現類,一般為AsyncHttpResponseHandler的子類,AsyncHttpClient內部有一個線程池,當使用AsyncHttpClient執行網絡請求時,最終都會調用sendRequest方法,在這個方法內部將請求參數封裝成AsyncHttpRequest(繼承自Runnable)交由內部的線程池執行。

SyncHttpClient 繼承自AsyncHttpClient,同步執行網絡請求,AsyncHttpClient把請求封裝成AsyncHttpRequest後提交至線程池,SyncHttpClient把請求封裝成AsyncHttpRequest後直接調用它的run方法。

AsyncHttpRequest 繼承自Runnabler,被submit至線程池執行網絡請求並發送start,success等消息。

AsyncHttpResponseHandler 接收請求結果,一般重寫onSuccess及onFailure接收請求成功或失敗的消息,還有onStart,onFinish等消息。

TextHttpResponseHandler、JsonHttpResponseHandler、BaseJsonHttpResponseHandler這些類都繼承自AsyncHttpResponseHandler,只是重寫了AsyncHttpResponseHandler的onSuccess和onFailure方法,將請求結果進行了轉換而已。

RequestParams 請求參數,可以添加普通的字符串參數,並可添加File,InputStream上傳文件。


 

 



 

 
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved