安卓網路請求框架第三彈——OkHttp的封裝
阿新 • • 發佈:2019-01-01
概述:此篇為Android網路請求框架第三彈,底層請求用的是okhttp 基本機構來自包建強老師的app研發錄,在研發錄中,包老師使用的是HttpClient,但是由於google在Android4.0之後刪除了HttpClient的APi,所以在包老師的基礎,加以修改,使用okHttp作為請求方式。建議沒讀過包老師APP研發錄的同學,先去研究一下此書,對我的幫助還是很大的。傳送門:包老師部落格地址 原始碼下載
一 本框架的核心內容就是:用執行緒池來管理我們的網路請求。不使用Asynctask的原因就是Asynctask不能靈活控制其內部的執行緒池。Asynctask沒有暴露出取消請求的方法。我們使用 ThreadPoolExecutor+Runnable+Handler的原生方式進行網路底層封裝。
1 URLData和UrlConfigManager
urlData 是我們自定義的請求實體
/**
* 介面名
*/
private String key;
/**
* 資料快取時間
*/
private long expires;
/**
* 請求方式 get或者post
*/
private String netType;
/**
* 請求地址
*/
private String url;
urlConfigManager是將關於介面的xml配置檔案 轉換成urldata放入ArrayList中 xml檔案如下
<Node
Expires="300"
Key="getWeatherInfo"
NetType="get"
Url="http://www.weather.com.cn/data/sk/101010100.html" />
2 RemoteService和RequestCallback,RequestParameter。RequestManager,DefaultThreadPool
RequestCallback callback = new RequestCallback() {
@Override
public void onSuccess(String content) {
Log.i("content", content);
}
@Override
public void onFail(String errorMessage) {
Log.i("error", errorMessage);
}
@Override
public void onCookieExpired() {
}
};
ArrayList<RequestParameter> parameters = new ArrayList<>();
RequestParameter parameter1 = new RequestParameter("k1", "v1");
RequestParameter parameter2 = new RequestParameter("k1", "v1");
parameters.add(parameter1);
parameters.add(parameter2);
RemoteService.getInstance().invoke(this, "serverDemo", parameters, callback);
a RequestCallback是回撥,有onSuccess和onFail兩個方法。
b RequestParameter是用來傳遞呼叫介面所需要引數鍵值對的,當然你也可以使用HashMap
c RemoteService這個單例是用來發起請求的,它會建立一個request並將它新增到requestManager中 然後放到DefaultThreadPool的一個執行緒中去執行這個request。
d requestManager這個集合類是用於取消請求(cancelRequest)的,因為每發起一個請求,都會新增到RequestManager中,所以RequestManager儲存了全部Request ,所以在從ActivityA 跳轉到ActivityB,為了不產生阻塞,所以要取消ActivityA中所有未完成的Request 。
* 取消網路請求
*/
public void cancelRequest() {
if ((requestList != null) && (requestList.size() > 0)) {
for (final OkHttpRequest request : requestList) {
if (request.getCall() != null) {
try {
request.getCall().cancel();
requestList.remove(request);
} catch (final UnsupportedOperationException e) {
e.printStackTrace();
}
}
}
}
}`
我們在BaseAcitivty中,會保持對RequestManager一個引用,這樣在onDestroy和onPause的時候執行cancelRequest方法取消所有未完成的請求。
e DefaultThreadPool只是對ThreadPoolExecutor和ArrayBlockingQueue的簡單封裝。我們可以認為它就是一個執行緒池,每發起一個請求,就由執行緒池分配一個新的執行緒來執行該請求。
3 OkHttpRequest 這個類 就是我自己寫的代替了以前的HttpClient 。在這個類中,整體的架構設計沒有改變。它實現了Runable介面,提供一個run方法來執行請求。
a 第一步 還是根據urlConfigManager得到的urlData來區分get還是post來建立一個request請求。
b 第二步 設定請求超時時間,讀寫時間,新增cookie到請求頭中,新增必要頭部資訊到請求頭中。
okBuilder.connectTimeout(4000, TimeUnit.MILLISECONDS)
.readTimeout(4000, TimeUnit.MILLISECONDS)
.writeTimeout(4000, TimeUnit.MILLISECONDS);
addCookie();// 新增Cookie到請求頭中
setHttpHeaders(okBuilder); //新增必要的頭部資訊
mOkHttpClient = okBuilder.build();
c 發起請求,使用requestCallback 處理返回結果。
//傳送請求
call = mOkHttpClient.newCall(request);
//結果回撥
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, final IOException e) {
if (requestCallback != null) {
handler.post(new Runnable() {
@Override
public void run() {
requestCallback.onFail(e.getMessage());
}
});
} else {
// TODO: 2016/11/24 處理介面為空的情況
}
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (requestCallback != null) {
int code = response.code();
if (code >= 200 && code < 300) { //代表成功
// updateDeltaBetweenServerAndClientTime(response); // 更新伺服器時間和本地時間的差值
//okHttp3 如果在頭部中 添加了 gzip欄位 會自動進行 gzip 解壓 這裡不在處理
String string = response.body().string();
Log.i("DataResponse", string);
final DataResponse dataResponse = JSON.parseObject(string, DataResponse.class);
if (dataResponse.hasError()) { // 包含錯誤
if (dataResponse.getErrorType() == 1) {
handler.post(new Runnable() {
@Override
public void run() {
requestCallback.onCookieExpired();
}
});
} else {
handleNetworkError(dataResponse.getErrorMessage());
}
} else {
//當是get請求 並且快取時間>0時 儲存到快取
if (urlData.getNetType().equals(REQUEST_GET) && urlData.getExpires() > 0) {
CacheManager.getInstance().putFileCache(newUrl, dataResponse.getResult(), urlData.getExpires());
}
handler.post(new Runnable() {
@Override
public void run() {
requestCallback.onSuccess(dataResponse.getResult() + " success");
}
});
}
} else {
handleNetworkError("網路異常2");
}
} else {
// TODO: 2016/11/24 處理介面為空的情況
}
}
});
d 在本類中,還介紹了關於 cookie的持久化處理,這裡不做贅述。
/**
* 從本地獲取cookie列表
*
* @return
*/
public void addCookie() {
okBuilder.cookieJar(new CookiesManager());
}
/**
* 自動管理Cookies
*/
private class CookiesManager implements CookieJar {
private final PersistentCookieStore cookieStore = new PersistentCookieStore(activity);
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
if (cookies != null && cookies.size() > 0) {
for (Cookie item : cookies) {
cookieStore.add(url, item);
}
}
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> cookies = cookieStore.get(url);
return cookies;
}
}