Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android-async-http封裝網絡請求框架源碼分析

Android-async-http封裝網絡請求框架源碼分析

編輯:關於Android編程

Android-async-http開源項目可以是我們輕松的獲取網絡數據或者向服務器發送數據,使用起來非常簡單, 這個網絡請求庫是基於Apache HttpClient庫之上的一個異步網絡請求處理庫,網絡處理均基於Android的非UI線程,通過回調方法處理請求結果.

主要特點:處理異步Http請求,並通過匿名內部類處理回調結果,Http異步請求均位於非UI線程,不會阻塞UI操作,通過線程池處理並發請求處理文件上傳、下載,響應結果自動打包JSON格式.

一,Android-async-http的項目鏈接

Github地址:https://github.com/loopj/android-async-http

V1.4.9的javadoc: https://loopj.com/android-async-http/doc/

在DowloadZip下載zip包解壓後是Android Studio工程的目錄如下:

\

examples:裡面有簡單的例子
library:裡面存放的是android-async-http開源項目的源碼(方法一:可以把library\src\main\Java文件下面的文件拷貝到,你應用的src下也可以直接使用)
releases:裡面存放的是各個版本的jar文件,(方法二:只需把最新的jar文件拷貝到你應用的libs目錄下即可.)
samples:裡面存放的也是例子(可供參考)
備注:方法一和方法二只能采用其中之一,建議采用方法二

二,主要特性

1,Make asynchronous HTTP requests, handle responses in anonymous callbacks
異步http請求,匿名回調處理響應
2,HTTP requests happen outside the UI thread
在UI線程之外進行HTTP請求
3,Requests use a threadpool to cap concurrent resource usage
請求使用線程池,限制使用資源並發情況
4,GET/POST params builder (RequestParams)
使用RequestParams封裝GET/POST請求參數
5,Multipart file uploads with no additional third party libraries
不使用第三方庫多任務上傳
6,Tiny size overhead to your application, only 60kb for everything
占用應用的控件少只需要60kb
7,Automatic smart request retries optimized for spotty mobile connections
自動智能重試請求
8,Optional built-in response parsing into JSON (JsonHttpResponseHandler)
內置響應解析成JSON,使用JsonHttpResponseHandler
9,Optional persistent cookie store, saves cookies into your app's SharedPreferences
有選擇的持久化cookie存儲,保存在app的SharedPreferences文件

三,核心類介紹

對於http請求網絡的方式,無非就解決三個問題,第一,請求客戶端的方法,第二,請求參數的封裝,第三,請求響應的接收處理
先來看一下最基本的用法好有個大概的了解

AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
    @Override
    public void onSuccess(String response) {
        System.out.println(response);
    }
});
1,Http客戶端是誰?AsyncHttpClient

 

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

2,封裝的請求對象是誰?
AsyncHttpRequest:繼承自Runnabler,被submit至線程池執行網絡請求並發送start,success等消息

3,請求參數和url怎麼封裝?
RequestParams:請求參數,可以添加普通的字符串參數,並可添加File,InputStream上傳文件,內部使用Map添加Key-Value


3,Http請求怎樣被執行?

AsyncHttpClient對象執行get等方法,將Context,Url,RequestParams,responseHandler等參數傳入,在get()方法內部又封裝成sendRequest方法,sendRequest方法內又封裝請求AsyncHttpRequest,被提交到線程池的阻塞隊列,等待執行,AsyncHttpRequest實現了Runnable方法,線程執行run()方法,在run方法內,responseHandler可以調用sendStartMessage(),makeRequestWithRetries(),sendFinishMessage()記錄任務執行的過程日志Log,在執行makeRequestWithRetries方法中執行真正的網絡執行語句HttpResponse response = client.execute(request, context);之後響應處理者調用sendResponseMessage(response),發送響應消息,最終轉到OnSuccess(int statusCode, Header[] headers, byte[] responseBody);響應處理者子類只需要重寫這個方法,對返回的響應做響應的處理

 

4,請求響應用什麼方式處理?AsyncHttpResponseHandler, TextHttpResponseHandler, JsonHttpResponseHandler, BaseJsonHttpResponseHandler

繼承圖

\
AsyncHttpResponseHandler:

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

 

	 //這個方法是子類必須重寫的方法,來處理響應的
    public abstract void onSuccess(int statusCode, Header[] headers, byte[] responseBody);

    /**
     * Fired when a request fails to complete, override to handle in your own code
     *
     * @param statusCode   return HTTP status code
     * @param headers      return headers, if any
     * @param responseBody the response body, if any
     * @param error        the underlying cause of the failure
     */
	 //這個方法是子類必須重寫的方法,來處理響應的
    public abstract void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error);

BinaryHttpResponseHandler extends AsyncHttpResponseHandler :

 

繼承AsyncHttpResponseHandler的子類,這是一個字節流返回處理的類, 該類用於處理圖片,流的形式;

 

    @Override
    public abstract void onSuccess(int statusCode, Header[] headers, byte[] binaryData);

    @Override
    public abstract void onFailure(int statusCode, Header[] headers, byte[] binaryData, Throwable error);

TextHttpResponseHandler:

 

繼承自AsyncHttpResponseHandler,只是重寫了AsyncHttpResponseHandler的onSuccess和onFailure方法,將請求結果由byte數組轉換為String

 

    /**
     * Called when request fails
     *
     * @param statusCode     http response status line
     * @param headers        response headers if any
     * @param responseString string response of given charset
     * @param throwable      throwable returned when processing request
     */
    public abstract void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable);

    /**
     * Called when request succeeds
     *
     * @param statusCode     http response status line
     * @param headers        response headers if any
     * @param responseString string response of given charset
     */
    public abstract void onSuccess(int statusCode, Header[] headers, String responseString);

JsonHttpResponseHandler:

 

繼承自TextHttpResponseHandler,是一個泛型類,提供了parseResponse方法,子類需要提供實現,將請求結果解析成需要的類型,子類可以靈活地使用解析方法,可以直接原始解析,使用gson等。

 

 /**
     * Returns when request succeeds
     *
     * @param statusCode http response status line
     * @param headers    response headers if any
     * @param response   parsed response if any
     */
    public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
        AsyncHttpClient.log.w(LOG_TAG, "onSuccess(int, Header[], JSONObject) was not overriden, but callback was received");
    }

    /**
     * Returns when request succeeds
     *
     * @param statusCode http response status line
     * @param headers    response headers if any
     * @param response   parsed response if any
     */
    public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
        AsyncHttpClient.log.w(LOG_TAG, "onSuccess(int, Header[], JSONArray) was not overriden, but callback was received");
    }

    /**
     * Returns when request failed
     *
     * @param statusCode    http response status line
     * @param headers       response headers if any
     * @param throwable     throwable describing the way request failed
     * @param errorResponse parsed response if any
     */
    public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
        AsyncHttpClient.log.w(LOG_TAG, "onFailure(int, Header[], Throwable, JSONObject) was not overriden, but callback was received", throwable);
    }

    /**
     * Returns when request failed
     *
     * @param statusCode    http response status line
     * @param headers       response headers if any
     * @param throwable     throwable describing the way request failed
     * @param errorResponse parsed response if any
     */
    public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONArray errorResponse) {
        AsyncHttpClient.log.w(LOG_TAG, "onFailure(int, Header[], Throwable, JSONArray) was not overriden, but callback was received", throwable);
    }

    @Override
    public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
        AsyncHttpClient.log.w(LOG_TAG, "onFailure(int, Header[], String, Throwable) was not overriden, but callback was received", throwable);
    }

    @Override
    public void onSuccess(int statusCode, Header[] headers, String responseString) {
        AsyncHttpClient.log.w(LOG_TAG, "onSuccess(int, Header[], String) was not overriden, but callback was received");
    }
 /**
     * Returns Object of type {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer, Long,
     * Double or {@link JSONObject#NULL}, see {@link org.json.JSONTokener#nextValue()}
     *
     * @param responseBody response bytes to be assembled in String and parsed as JSON
     * @return Object parsedResponse
     * @throws org.json.JSONException exception if thrown while parsing JSON
     */
    protected Object parseResponse(byte[] responseBody) throws JSONException {
        if (null == responseBody)
            return null;
        Object result = null;
        //trim the string to prevent start with blank, and test if the string is valid JSON, because the parser don't do this :(. If JSON is not valid this will return null
        String jsonString = getResponseString(responseBody, getCharset());
        if (jsonString != null) {
            jsonString = jsonString.trim();
            if (useRFC5179CompatibilityMode) {
                if (jsonString.startsWith("{") || jsonString.startsWith("[")) {
                    result = new JSONTokener(jsonString).nextValue();
                }
            } else {
                // Check if the string is an JSONObject style {} or JSONArray style []
                // If not we consider this as a string
                if ((jsonString.startsWith("{") && jsonString.endsWith("}"))
                        || jsonString.startsWith("[") && jsonString.endsWith("]")) {
                    result = new JSONTokener(jsonString).nextValue();
                }
                // Check if this is a String "my String value" and remove quote
                // Other value type (numerical, boolean) should be without quote
                else if (jsonString.startsWith("\"") && jsonString.endsWith("\"")) {
                    result = jsonString.substring(1, jsonString.length() - 1);
                }
            }
        }
        if (result == null) {
            result = jsonString;
        }
        return result;
    }

四,原理流程圖

 

\
1,調用AsyncHttpClient的get或post等方法發起網絡請求
2,所有的請求都走了sendRequest,在sendRequest中把請求封裝為AsyncHttpRequest,並添加到線程池執行,

3,當請求被執行時(即AsyncHttpRequest的run方法),執行AsyncHttpRequest的makeRequestWithRetries方法執行實際的請求,當請求失敗時可以重試。並在請求開始,結束,成功或失敗時向請求時傳的ResponseHandlerInterface實例發送消息

4,基本上使用的都是AsyncHttpResponseHandler的子類,調用其onStart,onSuccess等方法返回請求結果

五,核心源碼解讀

1,AsyncHttpClient.java

 

以Get方法為例分析源碼:
/**
     * Perform a HTTP GET request, without any parameters.
     * 執行一個沒有參數的HTTP Get請求
     * @param url             the URL to send the request to.  請求Url
     * @param responseHandler the response handler instance that should handle the response.處理響應對象
     * @return RequestHandle of future request process
     */
    public RequestHandle get(String url, ResponseHandlerInterface responseHandler) {
        return get(null, url, null, responseHandler);//轉到另一個重載函數,四個參數是Context,Url,RequestParams,ResponseHandler
    }

    // [-] HTTP GET
    // [+] HTTP POST

    /**
     * Perform a HTTP GET request with parameters.
     *執行一個有參數的HTTP Get請求
     * @param url             the URL to send the request to.
     * @param params          additional GET parameters to send with the request.
     * @param responseHandler the response handler instance that should handle the response.
     * @return RequestHandle of future request process
     */
    public RequestHandle get(String url, RequestParams params, ResponseHandlerInterface responseHandler) {
        return get(null, url, params, responseHandler);//轉到另一個重載函數,四個參數是Context,Url,RequestParams,ResponseHandler
    }

    /**
     * Perform a HTTP GET request without any parameters and track the Android Context which
     * initiated the request.
     *
     * @param context         the Android Context which initiated the request.
     * @param url             the URL to send the request to.
     * @param responseHandler the response handler instance that should handle the response.
     * @return RequestHandle of future request process
     */
    public RequestHandle get(Context context, String url, ResponseHandlerInterface responseHandler) {
        return get(context, url, null, responseHandler);
    }

    /**
     * Perform a HTTP GET request and track the Android Context which initiated the request.
     *執行一個Http Get請求,有Context參數,初始化request
     * @param context         the Android Context which initiated the request.   // android上下文context
     * @param url             the URL to send the request to.//請去的url
     * @param params          additional GET parameters to send with the request.//請求的參數
     * @param responseHandler the response handler instance that should handle the response.//處理響應對象
     * @return RequestHandle of future request process
     */
    public RequestHandle get(Context context, String url, RequestParams params, ResponseHandlerInterface responseHandler) {
	  /*
	   *  封裝sendRequest的方法,感覺和HttpClient的方式相似,不是很懂,參數如下
	   *1,DefaultHttpClient httpClient
	   *2,HttpContext httpContext
	   *3,HttpGet httpget
	   *4,
	   *5,ResponseHandlerInterface responseHandler
	   *6,Context context
	   */
        return sendRequest(httpClient, httpContext, new HttpGet(getUrlWithQueryString(isUrlEncodingEnabled, url, params)), null, responseHandler, context);
    }

    /**
     * Perform a HTTP GET request and track the Android Context which initiated the request with
     * customized headers
     * 執行有自定義Header的請求
     * @param context         Context to execute request against
     * @param url             the URL to send the request to.
     * @param headers         set headers only for this request
     * @param params          additional GET parameters to send with the request.
     * @param responseHandler the response handler instance that should handle the response.
     * @return RequestHandle of future request process
     */
    public RequestHandle get(Context context, String url, Header[] headers, RequestParams params, ResponseHandlerInterface responseHandler) {
        HttpUriRequest request = new HttpGet(getUrlWithQueryString(isUrlEncodingEnabled, url, params));
        if (headers != null) request.setHeaders(headers);//自定義的Header加入到,HttpGet對象中
        return sendRequest(httpClient, httpContext, request, null, responseHandler,
                context);
    }

/**
     * 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
     */ 
	   /*
	   * 封裝sendRequest的方法,感覺和HttpClient的方式相似,不是很懂,參數如下
	   *1,DefaultHttpClient httpClient
	   *2,HttpContext httpContext
	   *3,HttpGet httpget
	   *4,String contentType,
	   *5,ResponseHandlerInterface responseHandler
	   *6,Context context
	   */
    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 && uriRequest.containsHeader(HEADER_CONTENT_TYPE)) {
                log.w(LOG_TAG, "Passed contentType will be ignored because HttpEntity sets content type");
            } else {
                uriRequest.setHeader(HEADER_CONTENT_TYPE, contentType);
            }
        }
        //responseHandler設置請求頭和請去Url
        responseHandler.setRequestHeaders(uriRequest.getAllHeaders());
        responseHandler.setRequestURI(uriRequest.getURI());
        //構造一個執行請求的AsyncHttpRequest對象,准備被發送到線程池的任務隊列,等待執行AsyncHttpRequest對象中的run方法
        AsyncHttpRequest request = newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context);
        threadPool.submit(request);//重點!!!!: 把AsyncHttpRequest對象提交到線程池等待執行
		/**
         * A Handle to an AsyncRequest which can be used to cancel a running request.
		 * 一個可以用來取消正在運行的請求的手柄或者說是操作者
         */
        RequestHandle requestHandle = new RequestHandle(request);

        if (context != null) {
            List requestList;
            // Add request to request map
            synchronized (requestMap) {
                requestList = requestMap.get(context);
                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;//返回手柄
    }
AsyncHttpRequest.java

 

 

/**
 * Internal class, representing the HttpRequest, done in asynchronous manner
 */
 //異步HTTP請求對象,實現的是Runnable接口,說明AsyncHttpRequest是一個供線程執行的任務類,主要關注run方法
public class AsyncHttpRequest implements Runnable {
    private final AbstractHttpClient client;//Http客戶端,Httpclient
    private final HttpContext context;
    private final HttpUriRequest request;//保存HttpGet對象
    private final ResponseHandlerInterface responseHandler;//保存響應處理者對象,可以跟蹤任務的執行,start,fihish等
    private final AtomicBoolean isCancelled = new AtomicBoolean();
    private int executionCount;
    private boolean cancelIsNotified;
    private volatile boolean isFinished;
    private boolean isRequestPreProcessed;

    public AsyncHttpRequest(AbstractHttpClient client, HttpContext context, HttpUriRequest request, ResponseHandlerInterface responseHandler) {
        this.client = Utils.notNull(client, "client");
        this.context = Utils.notNull(context, "context");
        this.request = Utils.notNull(request, "request");
        this.responseHandler = Utils.notNull(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... } /* * 在線程池中執行run方法過程 */ @Override public void run() { if (isCancelled()) { return; } // Carry out pre-processing for this request only once. if (!isRequestPreProcessed) { isRequestPreProcessed = true; onPreProcessRequest(this); } if (isCancelled()) { return; } //responseHandler發送開始消息,響應處理者設置start消息 responseHandler.sendStartMessage(); if (isCancelled()) { return; } try { //重點是這個方法!!! makeRequestWithRetries(); } catch (IOException e) { if (!isCancelled()) { //任務執行失敗,響應處理者設置failure消息 responseHandler.sendFailureMessage(0, null, null, e); } else { AsyncHttpClient.log.e("AsyncHttpRequest", "makeRequestWithRetries returned error", e); } } if (isCancelled()) { return; } //任務執行完成,響應處理者設置finish消息 responseHandler.sendFinishMessage(); if (isCancelled()) { return; } // Carry out post-processing for this request. //任務執行完畢,調用這個方法 onPostProcessRequest(this); isFinished = true; } //makeRequest 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"); } if (responseHandler instanceof RangeFileAsyncHttpResponseHandler) { ((RangeFileAsyncHttpResponseHandler) responseHandler).updateRequestHeaders(request); } //終於看到這一句了,感覺就是我們常用的HttpClient,HttpGet,HttpResponse模式 HttpResponse response = client.execute(request, context); if (isCancelled()) { return; } // Carry out pre-processing for this response. //翻譯是在返回響應之前預處理 responseHandler.onPreProcessResponse(responseHandler, response); if (isCancelled()) { return; } // The response is ready, handle it. //猜到就是把HttpResponse對象封裝到響應處理者responseHandler中,responseHandler中肯定有保存HttpResponse對象的變量 responseHandler.sendResponseMessage(response); if (isCancelled()) { return; } // Carry out post-processing for this response. //返回響應之後的後處理,一個請求就這麼處理完了,接下來只需要出去處理responseHandler就可以得到響應了 responseHandler.onPostProcessResponse(responseHandler, response); } //重點是這個方法!!!做請求帶有重試次數的 private void makeRequestWithRetries() throws IOException { boolean retry = true; IOException cause = null; HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler(); try { while (retry) { try { //重點是去makerequest 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(), e); //如果執行拋出異常,會重試連接,可能是這樣理解的 retry = (executionCount > 0) && retryHandler.retryRequest(e, ++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 // https://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); } if (retry) { responseHandler.sendRetryMessage(executionCount); } } } catch (Exception e) { // catch anything else to ensure failure message is propagated AsyncHttpClient.log.e("AsyncHttpRequest", "Unhandled exception origin cause", e); cause = new IOException("Unhandled exception: " + e.getMessage(), cause); } // cleaned up to throw IOException throw (cause); }AsyncHttpResponseHandler.java

 

 

  /**
     * Fired when the request is started, override to handle in your own code
     */
	/*asyncHttpRequst的run方法執行時調用sendStartMessage發送開始消息
	* 其實就是轉入這個OnStart函數,如果想跟蹤任務執行的話寫log就重寫這個方法
	*/
    public void onStart() {
        // default log warning is not necessary, because this method is just optional notification
    }

    /**
     * Fired in all cases when the request is finished, after both success and failure, override to
     * handle in your own code
     */
	 /*asyncHttpRequst的run方法執行時調用sendFinishMessage發送開始消息
	* 其實就是轉入這個onFinish函數,如果想跟蹤任務執行的話寫log就重寫這個方法
	*/
    public void onFinish() {
        // default log warning is not necessary, because this method is just optional notification
    }
    /*
	*asyncHttpRequst的run方法執行到makeRequest方法時,執行完畢會調用一下兩個函數
	*onPreProcessResponse 是指在返回響應之前的預處理
	*onPostProcessResponse 是指返回響應之後的處理
	*/
    @Override
    public void onPreProcessResponse(ResponseHandlerInterface instance, HttpResponse response) {
        // default action is to do nothing...
    }

    @Override
    public void onPostProcessResponse(ResponseHandlerInterface instance, HttpResponse response) {
        // default action is to do nothing...
    }

    /**
     * Fired when a request returns successfully, override to handle in your own code
     *
     * @param statusCode   the status code of the response 響應的響應碼
     * @param headers      return headers, if any  響應的Header頭信息
     * @param responseBody the body of the HTTP response from the server 響應體
     */
	 //這個方法是子類必須重寫的方法,來處理響應的
    public abstract void onSuccess(int statusCode, Header[] headers, byte[] responseBody);

    /**
     * Fired when a request fails to complete, override to handle in your own code
     *
     * @param statusCode   return HTTP status code
     * @param headers      return headers, if any
     * @param responseBody the response body, if any
     * @param error        the underlying cause of the failure
     */
	 //這個方法是子類必須重寫的方法,來處理響應的
    public abstract void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error);
  // Methods which emulate android's Handler and Message methods
    protected void handleMessage(Message message) {
        Object[] response;

        try {
            switch (message.what) {
                case SUCCESS_MESSAGE:
                    response = (Object[]) message.obj;
                    if (response != null && response.length >= 3) {
					   //調用onSuccess方法
                        onSuccess((Integer) response[0], (Header[]) response[1], (byte[]) response[2]);
                    } else {
                        AsyncHttpClient.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方法
                        onFailure((Integer) response[0], (Header[]) response[1], (byte[]) response[2], (Throwable) response[3]);
                    } else {
                        AsyncHttpClient.log.e(LOG_TAG, "FAILURE_MESSAGE didn't got enough params");
                    }
                    break;
                case START_MESSAGE:
				   //調用onStart方法
                    onStart();
                    break;
                case FINISH_MESSAGE:
				   //調用onFinish方法
                    onFinish();
                    break;
                case PROGRESS_MESSAGE:
                    response = (Object[]) message.obj;
                    if (response != null && response.length >= 2) {
                        try {
                            onProgress((Long) response[0], (Long) response[1]);
                        } catch (Throwable t) {
                            AsyncHttpClient.log.e(LOG_TAG, "custom onProgress contains an error", t);
                        }
                    } else {
                        AsyncHttpClient.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 {
                        AsyncHttpClient.log.e(LOG_TAG, "RETRY_MESSAGE didn't get enough params");
                    }
                    break;
                case CANCEL_MESSAGE:
				  //調用onFinish方法
                    onCancel();
                    break;
            }
        } catch (Throwable error) {
            onUserException(error);
        }
    }
  }
   /*asyncHttpRequst的run方法執行到makeRequest方法時,獲得HttpResponse後會調用如下方法sendResponseMessage
    *
    *
	**/
    @Override
    public void sendResponseMessage(HttpResponse response) throws IOException {
        // do not process if request has been cancelled
		//因為asyncHttpRequst在線程池中執行,先判斷線程
        if (!Thread.currentThread().isInterrupted()) {
		   //獲取狀態行
            StatusLine status = response.getStatusLine();
            byte[] responseBody;
			//獲取響應體的字節數組
            responseBody = getResponseData(response.getEntity());
            // additional cancellation check as getResponseData() can take non-zero time to process
            if (!Thread.currentThread().isInterrupted()) {
                if (status.getStatusCode() >= 300) {
				    //如果響應碼大於等於300,則發送失敗消息,失敗和成功消息是判斷響應碼發生的,開始和結束消息是任務執行發生的
                    sendFailureMessage(status.getStatusCode(), response.getAllHeaders(), responseBody, new HttpResponseException(status.getStatusCode(), status.getReasonPhrase()));
                } else {
				   //否則發送成功消息,參數是響應碼,響應頭信息,響應體
                    sendSuccessMessage(status.getStatusCode(), response.getAllHeaders(), responseBody);
                }
            }
        }
    }
AsyncRequestParams.java

 

 

public class RequestParams implements Serializable {

    public final static String APPLICATION_OCTET_STREAM =
            "application/octet-stream";

    public final static String APPLICATION_JSON =
            "application/json";

    protected final static String LOG_TAG = "RequestParams";
	//d都是用的是並發HashMap,Url的參數
    protected final ConcurrentHashMap urlParams = new ConcurrentHashMap();
	//各種流的參數HashMap
    protected final ConcurrentHashMap streamParams = new ConcurrentHashMap();
	//各種文件的參數HashMap
    protected final ConcurrentHashMap fileParams = new ConcurrentHashMap();
	//多文件的參數HashMap
    protected final ConcurrentHashMap> fileArrayParams = new ConcurrentHashMap>();
	//帶對象的Url的參數HashMap
    protected final ConcurrentHashMap urlParamsWithObjects = new ConcurrentHashMap();
    protected boolean isRepeatable;
    protected boolean forceMultipartEntity = false;
    protected boolean useJsonStreamer;
    protected String elapsedFieldInJsonStreamer = "_elapsed";
    protected boolean autoCloseInputStreams;
    protected String contentEncoding = HTTP.UTF_8;

    /**
     * Constructs a new empty {@code RequestParams} instance.
     */
    public RequestParams() {
        this((Map) null);
    }

    /**
     * Constructs a new RequestParams instance containing the key/value string params from the
     * specified map.
     *
     * @param source the source key/value string map to add.
     */
    public RequestParams(Map source) {
        if (source != null) {
            for (Map.Entry entry : source.entrySet()) {
                put(entry.getKey(), entry.getValue());
            }
        }
    }

    /**
     * Constructs a new RequestParams instance and populate it with a single initial key/value
     * string param.
     *
     * @param key   the key name for the intial param.
     * @param value the value string for the initial param.
     */
    public RequestParams(final String key, final String value) {
        this(new HashMap() {{
            put(key, value);
        }});
    }

    /**
     * Constructs a new RequestParams instance and populate it with multiple initial key/value
     * string param.
     *
     * @param keysAndValues a sequence of keys and values. Objects are automatically converted to
     *                      Strings (including the value {@code null}).
     * @throws IllegalArgumentException if the number of arguments isn't even.
     */
    public RequestParams(Object... keysAndValues) {
        int len = keysAndValues.length;
        if (len % 2 != 0)
            throw new IllegalArgumentException("Supplied arguments must be even");
        for (int i = 0; i < len; i += 2) {
            String key = String.valueOf(keysAndValues[i]);
            String val = String.valueOf(keysAndValues[i + 1]);
            put(key, val);
        }
    }

    /**
     * Sets content encoding for return value of {@link #getParamString()} and {@link
     * #createFormEntity()}

 

Default encoding is "UTF-8" * * @param encoding String constant from {@link HTTP} */ public void setContentEncoding(final String encoding) { if (encoding != null) { this.contentEncoding = encoding; } else { AsyncHttpClient.log.d(LOG_TAG, "setContentEncoding called with null attribute"); } } /** * If set to true will force Content-Type header to `multipart/form-data` * even if there are not Files or Streams to be send *

 

* Default value is false * * @param force boolean, should declare content-type multipart/form-data even without files or streams present */ public void setForceMultipartEntityContentType(boolean force) { this.forceMultipartEntity = force; } /** * Adds a key/value string pair to the request. * * @param key the key name for the new param. * @param value the value string for the new param. */ public void put(String key, String value) { if (key != null && value != null) { urlParams.put(key, value); } } /** * Adds files array to the request. * * @param key the key name for the new param. * @param files the files array to add. * @throws FileNotFoundException if one of passed files is not found at time of assembling the requestparams into request */ public void put(String key, File files[]) throws FileNotFoundException { put(key, files, null, null); } /** * Adds files array to the request with both custom provided file content-type and files name * * @param key the key name for the new param. * @param files the files array to add. * @param contentType the content type of the file, eg. application/json * @param customFileName file name to use instead of real file name * @throws FileNotFoundException throws if wrong File argument was passed */ public void put(String key, File files[], String contentType, String customFileName) throws FileNotFoundException { if (key != null) { List fileWrappers = new ArrayList(); for (File file : files) { if (file == null || !file.exists()) { throw new FileNotFoundException(); } fileWrappers.add(new FileWrapper(file, contentType, customFileName)); } fileArrayParams.put(key, fileWrappers); } } /** * Adds a file to the request. * * @param key the key name for the new param. * @param file the file to add. * @throws FileNotFoundException throws if wrong File argument was passed */ public void put(String key, File file) throws FileNotFoundException { put(key, file, null, null); } /** * Adds a file to the request with custom provided file name * * @param key the key name for the new param. * @param file the file to add. * @param customFileName file name to use instead of real file name * @throws FileNotFoundException throws if wrong File argument was passed */ public void put(String key, String customFileName, File file) throws FileNotFoundException { put(key, file, null, customFileName); } /** * Adds a file to the request with custom provided file content-type * * @param key the key name for the new param. * @param file the file to add. * @param contentType the content type of the file, eg. application/json * @throws FileNotFoundException throws if wrong File argument was passed */ public void put(String key, File file, String contentType) throws FileNotFoundException { put(key, file, contentType, null); } /** * Adds a file to the request with both custom provided file content-type and file name * * @param key the key name for the new param. * @param file the file to add. * @param contentType the content type of the file, eg. application/json * @param customFileName file name to use instead of real file name * @throws FileNotFoundException throws if wrong File argument was passed */ public void put(String key, File file, String contentType, String customFileName) throws FileNotFoundException { if (file == null || !file.exists()) { throw new FileNotFoundException(); } if (key != null) { fileParams.put(key, new FileWrapper(file, contentType, customFileName)); } } /** * Adds an input stream to the request. * * @param key the key name for the new param. * @param stream the input stream to add. */ public void put(String key, InputStream stream) { put(key, stream, null); } /** * Adds an input stream to the request. * * @param key the key name for the new param. * @param stream the input stream to add. * @param name the name of the stream. */ public void put(String key, InputStream stream, String name) { put(key, stream, name, null); } /** * Adds an input stream to the request. * * @param key the key name for the new param. * @param stream the input stream to add. * @param name the name of the stream. * @param contentType the content type of the file, eg. application/json */ public void put(String key, InputStream stream, String name, String contentType) { put(key, stream, name, contentType, autoCloseInputStreams); } /** * Adds an input stream to the request. * * @param key the key name for the new param. * @param stream the input stream to add. * @param name the name of the stream. * @param contentType the content type of the file, eg. application/json * @param autoClose close input stream automatically on successful upload */ public void put(String key, InputStream stream, String name, String contentType, boolean autoClose) { if (key != null && stream != null) { streamParams.put(key, StreamWrapper.newInstance(stream, name, contentType, autoClose)); } } /** * Adds param with non-string value (e.g. Map, List, Set). * * @param key the key name for the new param. * @param value the non-string value object for the new param. */ public void put(String key, Object value) { if (key != null && value != null) { urlParamsWithObjects.put(key, value); } } /** * Adds a int value to the request. * * @param key the key name for the new param. * @param value the value int for the new param. */ public void put(String key, int value) { if (key != null) { urlParams.put(key, String.valueOf(value)); } } /** * Adds a long value to the request. * * @param key the key name for the new param. * @param value the value long for the new param. */ public void put(String key, long value) { if (key != null) { urlParams.put(key, String.valueOf(value)); } } /** * Adds string value to param which can have more than one value. * * @param key the key name for the param, either existing or new. * @param value the value string for the new param. */ public void add(String key, String value) { if (key != null && value != null) { Object params = urlParamsWithObjects.get(key); if (params == null) { // Backward compatible, which will result in "k=v1&k=v2&k=v3" params = new HashSet(); this.put(key, params); } if (params instanceof List) { ((List

六,使用方法

 

官方建議:Recommended Usage: Make a Static Http Client

 

import com.loopj.android.http.*;

public class TwitterRestClient {
  private static final String BASE_URL = "https://api.twitter.com/1/";

  private static AsyncHttpClient client = new AsyncHttpClient();

  public static void get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
      client.get(getAbsoluteUrl(url), params, responseHandler);
  }

  public static void post(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
      client.post(getAbsoluteUrl(url), params, responseHandler);
  }

  private static String getAbsoluteUrl(String relativeUrl) {
      return BASE_URL + relativeUrl;
  }
}
AsyncRequestParams.java'

 

 

RequestParams params = new RequestParams();
params.put("username", "yanbober");
params.put("password", "123456");
params.put("email", "[email protected]");

/*
* Upload a File
*/
params.put("file_pic", new File("test.jpg"));
params.put("file_inputStream", inputStream);
params.put("file_bytes", new ByteArrayInputStream(bytes));

/*
* url params: "user[first_name]=jesse&user[last_name]=yan"
*/
Map map = new HashMap();
map.put("first_name", "jesse");
map.put("last_name", "yan");
params.put("user", map);

/*
* url params: "what=haha&like=wowo"
*/
Set set = new HashSet();
set.add("haha");
set.add("wowo");
params.put("what", set);

/*
* url params: "languages[]=Java&languages[]=C"
*/
List list = new ArrayList();
list.add("Java");
list.add("C");
params.put("languages", list);

/*
* url params: "colors[]=blue&colors[]=yellow"
*/
String[] colors = { "blue", "yellow" };
params.put("colors", colors);

/*
* url params: "users[][age]=30&users[][gender]=male&users[][age]=25&users[][gender]=female"
*/
List> listOfMaps = new ArrayList>();
Map user1 = new HashMap();
user1.put("age", "30");
user1.put("gender", "male");

Map user2 = new HashMap();
user2.put("age", "25");
user2.put("gender", "female");

listOfMaps.add(user1);
listOfMaps.add(user2);

params.put("users", listOfMaps);

/*
* 使用實例
*/
AsyncHttpClient client = new AsyncHttpClient();
client.post("http://localhost:8080/androidtest/", params, responseHandler)
JsonHttpResponseHandler帶Json參數的POST:
try {
    JSONObject jsonObject = new JSONObject();
    jsonObject.put("username", "ryantang");
    StringEntity stringEntity = new StringEntity(jsonObject.toString());
    client.post(mContext, "http://api.com/login", stringEntity, "application/json", new JsonHttpResponseHandler(){
        @Override
        public void onSuccess(JSONObject jsonObject) {
            super.onSuccess(jsonObject);
        }
    });
} catch (JSONException e) {
    e.printStackTrace();
} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}
BinaryHttpResponseHandler下載文件:

 

 

client.get("http://download/file/test.java", new BinaryHttpResponseHandler() {
    @Override
    public void onSuccess(byte[] arg0) {
        super.onSuccess(arg0);
        File file = Environment.getExternalStorageDirectory();
        File file2 = new File(file, "down");
        file2.mkdir();
        file2 = new File(file2, "down_file.jpg");
        try {
            FileOutputStream oStream = new FileOutputStream(file2);
            oStream.write(arg0);
            oStream.flush();
            oStream.close();
        } catch (Exception e) {
            e.printStackTrace();
            Log.i(null, e.toString());
        }
    }
});
支持相應文件圖片上傳的話:
String path="http://sv1.livechano.com:8080/upload.action?&action=1.6&type=1&ext=png";
        File myFile = new File("/sdcard/test.png");
        RequestParams params = new RequestParams();
        try {

            params.put("image", myFile,"application/octet-stream");
            
            AsyncHttpClient client = new AsyncHttpClient();
            
            client.post(path, params, new AsyncHttpResponseHandler(){
                
                @Override
                public void onFailure(Throwable error, String content) {
                    // TODO Auto-generated method stub
                    super.onFailure(error, content);
                    Toast.makeText(MainActivity.this, "上傳失敗!"+content, Toast.LENGTH_LONG).show();
                }
                
                @Override
                public void onSuccess(int statusCode, String content) {
                    // TODO Auto-generated method stub
                    super.onSuccess(statusCode, content);
                    System.out
                            .println("content:    "+content);
                    Toast.makeText(MainActivity.this, "上傳成功!"+content, Toast.LENGTH_LONG).show();
                }
                
                
            });
            
        } catch(FileNotFoundException e) {
            
        }
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved