android-async-http 源码分析
android-async-http是一個為Android量身定制的異步HTTP請求框架,它基于Apache的HttpClient開發。本文針對v1.4.6版本進行分析。
1. 功能介紹
android-async-http中所有的HTTP請求都在主線程外的其他線程中執行,所有的請求回調都在創建該回調對象的線程中進行,所以不論在什么地方發起請求,系統都能夠正確地進行處理。android-async-http的特性總結如下:
- 異步網絡請求,在匿名回調中處理響應
- 使用線程池來限制并發請求的數量
- GET/POST請求參數的builder構造
- Multipart文件上傳
- 較小的體積,僅60KB
- 自動請求重發優化
- 支持gzip格式自動解壓縮
- 可選的內置Json解析
- 可選的Cookie持久化存儲
1.1 基本使用
android-async-http的使用比較簡單,實例化一個AsyncHttpClient對象,然后調用其get()/post()等方法傳入URL和請求參數還有一個回調處理對象,就可以發送HTTP請求。
AsyncHttpClient client = new AsyncHttpClient(); client.get("http://www.google.com", new AsyncHttpResponseHandler() {@Overridepublic void onStart() {// called before request is started}@Overridepublic void onSuccess(int statusCode, Header[] headers, byte[] response) {// called when response HTTP status is "200 OK"}@Overridepublic void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {// called when response HTTP status is "4XX" (eg. 401, 403, 404)}@Overridepublic void onRetry(int retryNo) {// called when request is retried} });2. 總體設計
2.1 概述
android-async-http的結構比較簡單,整體可以分解成三層,最上一層負責由客戶端代碼調用發送請求,第二層負責請求的封裝和執行,最下一層負責處理HTTP響應。
- AsyncHttpClient:調用此客戶端類中的方法發送異步HTTP請求。
- RequestParams:HTTP請求參數集合,可包含文件和數據流。
- AsyncHttpRequest:代表異步HTTP請求,作為線程執行對象。
- AsyncHttpResponseHandler:提供基本的HTTP響應處理。
- RequestHandle:HTTP請求的句柄,用于取消請求。
2.2 工作流程
客戶端調用AsyncHttpClient中的方法,傳入URL和請求參數RequestParams發送請求,請求被封裝成一個AsyncHttpRequest對象,這個對象代表一個異步請求,把請求加入到隊列中等待執行,執行請求的過程中通過調用客戶端傳入的回調接口,發送消息通知客戶端請求執行的情況。
3. 詳細設計
android-async-http框架建立在Apache的HttpClient庫之上,對HttpClient的類庫進行了包裝和升級,諸如HTTP請求失敗重試機制,multipart/form-data和Json請求體的支持,HTTP響應的處理與包裝。
此外還針對Android平臺的一些特性進行優化,包括利用線程池技術執行HTTP請求以避免阻塞UI線程,在請求響應時利用Android的消息機制在UI線程執行處理代碼,還利用了SharedPreferences持久化存儲Cookie。
3.1 發送HTTP請求
AsyncHttpClient是框架中的核心類,所有的HTTP請求都通過這個類發送。它有一系列get(),?post(),?put(),?delete(),?head()方法,分別代表HTTP協議的GET,POST,PUT,DELETE,HEAD請求。這些方法最終都會調用sendRequest()方法,這個方法會把一個HTTP請求包裝成一個線程對象放入請求隊列等待執行。
AsyncHttpRequest request = newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context); threadPool.submit(request);newAsyncHttpRequest()方法創建一個AsyncHttpRequest對象,AsyncHttpRequest類實現了Runnable接口,它代表一個異步請求,在run()方法中實現了具體的HTTP訪問。
發送請求的流程圖如下:
3.2 取消HTTP請求
在sendRequest()方法中,當把AsyncHttpRequest對象提交之后,會創建一個HTTP請求的句柄RequestHandle,之后作為返回值返回。
通過這個句柄可以操縱這個HTTP請求,句柄類中提供了cancel()方法可以取消這個請求,這個方法委托調用AsyncHttpRequest的cancel()方法,在HTTP請求的執行過程中,設置了許多檢查點,如果在執行過程中檢測到取消標識,則發送通知給回調對象,并且終止HTTP請求的執行。
除了可以取消某個具體的請求,android-async-http還支持把一個HTTP請求對象和Android中的Context綁定,通過綁定Context,可以對一個Context相關的所有請求執行一些操作,例如,可以在Activity的onDestroy()方法中可以取消與在Activity中創建的所有請求。
private final Map<Context, List<RequestHandle>> requestMap;在AsyncHttpClient類中聲明了一個成員requestMap,它關聯了Context和HTTP請求的句柄,在構造方法中對其進行初始化。
每次調用sendRequest()方法發送HTTP請求,如果傳入的Context參數不為null,都會把這個請求句柄添加到Context相關的句柄鏈上。
在AsyncHttpClient中有兩個方法:cancelAllRequest(boolean)、cancelRequests(Context, booolean),前一個方法取消系統中所有的請求,后一個方法取消一個Context下的所有請求。
3.3 HTTP請求參數
RequestParams類封裝了HTTP請求參數的集合,在這個類中有大量put()方法,用于添加各種請求參數和請求實體。
發送GET或DELETE請求時,調用getParamString()方法把請求參數拼裝成URL中的查詢字符串;而發送POST或PUT請求時,調用getEntity()方法獲取請求實體,RequestParams支持三種類型的請求實體:
3.3.1 multipart/form-data請求體
multipart/form-data請求的基礎方法是POST,它的請求頭和請求體與普通的POST請求不同。普通的POST請求只能發送簡單的name-value對,而使用multipart/form-data可以對請求體進行包裝可以發送多個不同種類的請求體內容。
android-async-http對多文件上傳的支持,就是使用multipart/form-data格式對文件數據進行包裝。
SimpleMultipartEntity類繼承自HttpEntity類,這個類實現了對multipart/form-data格式請求體的封裝。
關于multipart/form-data請求的協議細節不多作介紹。
3.3.2 Json請求體
android-async-http還支持把請求參數包裝成Json格式的請求體,JsonStreamerEntity類繼承自HttpEntity類,這個類實現了把請求參數包裝成Json格式的數據,可以用來上傳文件和二進制數據。
3.4 執行HTTP請求
AsyncHttpRequest類代表一個異步HTTP請求,它封裝了執行HTTP請求的具體細節,并實現了Runnable接口,作為線程執行對象,以異步的方式進行HTTP訪問。
執行請求的流程圖如下:
makeRequest()方法中完成HTTP訪問,makeRequestWithRetries()方法調用makeRequest()方法,封裝了對異常的處理邏輯,并實現了請求的重試機制。
HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler();HttpRequestRetryHandler是Apache HttpClient提供的HTTP請求重發的處理接口,調用retryRequest()方法申請一次HTTP請求重發,如果retryRequest()返回true即表示申請通過可以發送,false反之。
android-async-http實現了自己的重發處理器RetryHandler,在AsyncHttpClient的構造方法做了初始化,默認最多重發5次,每次間隔1.5s。
httpClient.setHttpRequestRetryHandler(new RetryHandler(DEFAULT_MAX_RETRIES, DEFAULT_RETRY_SLEEP_TIME_MILLIS));3.4.1 重發處理機制
RetryHandler類中維護了一個黑白名單,黑白名單中存儲了異常類型,每次請求發送失敗都會拋出一個異常,根據這個黑白名單判斷是否重發請求。
調用retryRequest()方法傳入一個異常對象和一個整數,異常對象是在進行HTTP訪問時拋出的,整數表示請求重發的次數。在RetryHandler類的實現中,retryRequest()方法根據重發的次數和拋出的異常還有其它一些屬性,響應重發請求。
在makeRequestWithRetries()方法的實現中,利用一個while循環實現請求重發的機制。
請求重發的流程圖如下:
3.5 處理HTTP響應事件
ResponseHandlerInterface接口用于發送消息通知客戶端代碼處理請求執行過程發送的事件(請求的過程中會發送很多事件,包括開始事件、結束事件、成功事件、失敗事件、重發事件、取消事件、更新進度事件),它是一個處理HTTP響應的回調接口。AsyncHttpResponseHandler類是這個接口的直接實現,這個類實現了最基本的事件處理邏輯,還有很多其它具體的處理類都是基于這個類的包裝了幾個接口,以滿足一些特殊的需求。
HTTP請求事件的處理有兩種方式:同步和異步,同步方式會在執行請求的線程中直接調用回調方法,而異步方式則會在創建這個處理對象的線程中調用回調方法。
ResponseHandlerInterface接口中定義了一系列sendXXX()方法,這些方法在請求執行過程中被調用,用于發送事件,在AsyncHttpResponseHandler的實現中,這些sendXXX()方法調用了sendMessage()方法,sendMessage()方法中封裝了選擇同步或異步處理的邏輯。
protected void sendMessage(Message msg) {if (getUseSynchronousMode() || handler == null) {handleMessage(msg);} else if (!Thread.currentThread().isInterrupted()) { // do not send messages if request has been cancelledAssertUtils.asserts(handler != null, "handler should not be null!");handler.sendMessage(msg);} }handleMessage()方法模仿了Handler中的處理方法,在這個方法里面實現了具體的事件分發,根據事件類型調用相應的回調接口。
同步方式直接調用handleMessage()方法在當前線程中執行處理;異步方式使用了Handler,在構造方法中使用一個構造線程的Looper對象初始化了這個Handler,事件的處理委托給Handler進行。
處理請求事件的流程圖如下:
框架中其它處理類都繼承自AsyncHttpResponseHandler,例如:TextHttpResponseHandler、FileAsyncHttpResponseHandler,前者把二進制數據流編碼成字符串作為結果返回,后者把HTTP請求返回的結果寫入到文件,把文件對象作為結果返回。
3.6 持久化Cookie存儲
PersistentCookieStore類實現了Apache HttpClient的CookieStore接口,它通過SharedPreferences實現了Cookie在Android設備上的持久化存儲。
Cookie持久化的技術上,利用了Java的序列化機制,提供了一個Cookie包裝類:SerializableCookie,這個包裝類實現了Serializable接口。PersistentCookieStore類提供了對二進制字節數組和十六進制字符串的編碼和解碼方法。
添加時利用序列化機制把Cookie轉換成字節數組然后進行十六進制編碼,再存儲到SharedPreferences中;讀取時先進行逆向解碼,再利用對象輸入流ObjectInputStream獲取Cookie對象。
本文出自2dxgujun,轉載時請注明出處及相應鏈接。
總結
以上是生活随笔為你收集整理的android-async-http 源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android 开源框架之 Androi
- 下一篇: AsyncHttpClient 源码分析