如下是官方文檔描述此庫的特點: All requests are made outside of your app’s main UI thread, but any callback logic will be executed on the same thread as the callback ...
如下是官方文檔描述此庫的特點:
All requests are made outside of your app’s main UI thread, but any callback logic will be executed on the same thread as the callback was created using Android’s Handler message passing.
•Using upstream HttpClient of version 4.3.6 instead of Android provided DefaultHttpClient
•Compatible with Android API 23 and higher
•Make asynchronous HTTP requests, handle responses in anonymous callbacks
•HTTP requests happen outside the UI thread
•Requests use a threadpool to cap concurrent resource usage
•GET/POST params builder (RequestParams)
•Multipart file uploads with no additional third party libraries
•Streamed JSON uploads with no additional libraries
•Handling circular and relative redirects
•Tiny size overhead to your application, only 90kb for everything
•Automatic smart request retries optimized for spoĴy mobile connections
•Automatic gzip response decoding support for super-fast requests
•Binary protocol communication with BinaryHttpResponseHandler
•Built-in response parsing into JSON with JsonHttpResponseHandler
•Saving response directly into file with FileAsyncHttpResponseHandler
•Persistent cookie store, saves cookies into your app’s SharedPreferences
•Integration with Jackson JSON, Gson or other JSON (de)serializing libraries with BaseJsonHttpResponseHandler
•Support for SAX parser with SaxAsyncHttpResponseHandler
•Support for languages and content encodings, not just UTF-8
•1、相容Android API23或更高版本
•2、發送非同步的http請求,在匿名的回調callback中處理響應response
•3、Http的請求發生在主線程之外
•4、使用線程池處理併發請求
•5、使用RequestParams構造GET、POST請求參數
•6、流式Json上傳,無需三方庫支持
•7、能處理環形和相對重定向
•8、內置multiPart file 上傳,無需第三方庫支持
•9、相比app來說庫很小,僅僅只有90k
•10、針對移動連接自動智能的請求重試優化機制
•11、自動的gzip響應解碼
•12、支持位元組流響應處理 BinaryHttpResponseHandler
•13、內置Json文本響應處理 JsonHttpResponseHandler
•14、持久化Cookie信息,將Cookie信息保存在應用的SharedPreference中
•15、通過實現抽象類BaseJsonHttpResponseHandler可以無縫對接三方Json解析庫
•16、支持SAX解析器 SaxAsyncHttpResponseHandler
•17、支持各種語言和content編碼,不止是UTF-8
Android-Async-Http 源碼版本1.4.9
在AsyncHttpClient的構造方法中有對連接各種參數的設置,並實例化了一個預設的線程池threadPool(Executors.newCachedThreadPool)用於提交請求任務AsyncHttpRequest,接著初始化了httpClient,並給請求和響應添加了攔截器以實現自動的gzip解碼,調用AsyncHttpRequest實例的get post等方法時最終會調用sendRequest方法,sendRequest方法接收httpClient、responseHandler、uriRequest等參數,在方法內部會構造請求的AsyncHttpRequest對象(newAsyncHttpRequest),並通過threadPool.submit(request)方法提交到線程池中,何為非同步就體現在這裡。
AsyncHttpRequest實現了Runnable介面,它的run方法就是核心代碼,調用responseHandler.sendxxx 方法以實現各種方法回調和請求結果投遞,在makeRequestWithRetries中有重試的邏輯,具體在retryHandler中有重試次數的判斷,當重試次數超過最大值時(預設是5次),跳出while迴圈,這裡重試的邏輯和Volley中的處理類似 。
其中AsyncHttpClient中預設的線程池沒有核心線程,只有work線程,且工作線程的存活時間是60s,如果此種線程池不能滿足需要,可以實現自己的線程池,並調用setThreadPool方法。
其中在調用AsyncHttpClient中各種請求方法時,會傳入請求響應的各式xxxResponseHandler,針對不同的響應數據類型,有TextHttpResponseHandler、JsonHttpResponseHandler、FileHttpResponseHandler等,這些xxxResponseHandler中封裝了Handler和Looper,因為構造Handler是需要先有Looper的,而looper的初始化是在AsyncHttpResponseHandler構造函數中,
this.looper = looper == null ? Looper.myLooper() : looper,即如果沒有傳入looper則使用當前線程的looper(即創建xxxResponseHandler的線程,可能是主線程也可能是子線程)。 這些xxxResponseHandler都繼承自AsyncHttpResponseHandler類,並實現了
onSuccess(int statusCode, Header[] headers, byte[] responseBody) 和 onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error)方法,以處理不同返回數據類型的響應。
如上敘述印證了2 、3、4、10、11條結論。
---------------------------------------------------------------------------------------------------------------------------------------------
上傳圖片文件到chuantu.biz,代碼如下
AsyncHttpClient httpClient = new AsyncHttpClient(); RequestParams params = new RequestParams(); try { String filePath = getBaseContext().getExternalCacheDir().getPath() + File.separator + "IMG_20171106_202814.jpg"; File file = new File(filePath); if (file.exists()) { params.put("uploadimg", file, "image/jpeg"); } } catch (FileNotFoundException e) { e.printStackTrace(); } httpClient.setProxy("172.20.10.2", 8888); httpClient.post(this, "http://www.chuantu.biz/upload.php", /*headers,*/ params,/* null,*/ new TextHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, String responseBody) { printHeaders(headers); Log.d(TAG, responseBody); } @Override public void onFailure(int statusCode, Header[] headers, String responseBody, Throwable error) { } });
如上印證了5 、8 兩條特性。
上傳文件時,會調用RequestParams中的createMultipartEntity方法,其中SimpleMulitpartEntity的addPart方法會添加待寫入流中的文件信息,之後將文件內容的位元組寫入到流中,具體見SimpleMultipartEntity的writeTo方法,其中SimpleMultipartEntity類實現了HttpEntity介面,其中重寫了getContentType方法,此方法中返回標識性的header信息,Content-Type:multipart/form-data;boundary= xxxxxx, 分界線標識的字元串是在數字大小寫字元等字元中隨機抽取出來的30個字元組成。
需要註意到構造AsyncHttpRequest時最後的參數context, 如果context不為空,請求會被放到
Map中,以便在Activity onPause的時候或者onDestory的時候取消掉無用的請求等。
-------------------------------------------------------------------------------------------------------------------
BaseJsonHttpResponseHandler的使用
先添加Gson依賴,compile 'com.google.code.gson:gson:2.8.1'
這裡以kuaidi100的快遞數據為例:http://www.kuaidi100.com/query?type=xxx&postid=xxxx
先創建一個快遞數據類的實體(這裡欄位並不全,只是為了說明問題,具體可以自行調試介面)
public class Express { public String message; public String nu; public int isCheck; public String com; public int status; public int state; public Express(String message, String nu, int isCheck, String com, int status, int state) { this.message = message; this.nu = nu; this.isCheck = isCheck; this.com = com; this.status = status; this.state = state; } @Override public String toString() { return "Express{" + "message='" + message + '\'' + ", nu='" + nu + '\'' + ", isCheck=" + isCheck + ", com='" + com + '\'' + ", status=" + status + ", state=" + state + '}'; } }
創建RequestParams 發起GET請求
RequestParams params = new RequestParams(); params.put("type", "shunfeng"); params.put("postid", "384566812983"); httpClient.get("http://www.kuaidi100.com/query", params, new BaseJsonHttpResponseHandler<Express>() { @Override public void onSuccess(int statusCode, Header[] headers, String rawJsonResponse, Express response) { Log.d(TAG, "response = " + response); } @Override public void onFailure(int statusCode, Header[] headers, Throwable throwable, String rawJsonData, Express errorResponse) { } @Override protected Express parseResponse(String rawJsonData, boolean isFailure) throws Throwable { Gson gson = new Gson(); return gson.fromJson(rawJsonData, Express.class); } });