本文簡述了為什麼選擇okhttp作為自己的專案網路庫,和如何二次封裝為module便於使用
注:進階版MyOkHttp見文章:
0 Android架構系列文章
該系列文章會不斷更新Android專案開發中一些好的架構和小技巧
系列一 Android架構系列-基於MVP建立適合自己的架構
系列二 Android架構系列-如何優美的寫Intent
系列三 Android架構系列-開發規範
系列四 Android架構系列-封裝自己的okhttp
系列五 Android架構系列-MVP架構的實際應用
1 網路庫的選擇和為什麼放棄retrofit
本來專案的網路庫選擇的搭配是最流行的retrofit+okhttp+gson.如下圖版本庫裡還有記錄。
But!後來遇到了這樣的問題:服務端提供的API無法遵循Restful的API格式,而且不同模組由於分服務開發的,也不能保證格式一致。導致API介面層的實現十分牽強。最終api層的編寫不能專注於業務,適得其反。(最起碼現在的服務端還不適合與retrofit的使用)
最後決定放棄使用retrofit,使用自己二次封裝的okhttp。
2 封裝使用okhttp
封裝過程中參考了:
hongyang的Android OkHttp完全解析 是時候來了解OkHttp了
趙凱強的開源專案OkHttpPlus
2.1 怎麼使用
先說封裝好的okhttp+gson如何使用。(封裝了POST請求,GET請求,上傳檔案,下載檔案,取消請求和Gson轉換等功能)
2.1.1 POST請求
Map<String, String> params = new HashMap<String, String>();
params.put("name", "tsy");
MyOkHttp.get().post(this, "http://192.168.3.1/test_okhttp.php", params, new JsonResponseHandler() {
@Override
public void onSuccess(int statusCode, JSONObject response) {
LogUtils.v(TAG, statusCode + " " + response);
}
@Override
public void onFailure(int statusCode, String error_msg) {
LogUtils.v(TAG, statusCode + " " + error_msg);
}
});複製程式碼
2.1.2 GET請求
Map<String, String> params = new HashMap<String, String>();
params.put("name", "tsy");
MyOkHttp.get().get(this, "http://192.168.3.1/test_okhttp.php", params, new RawResponseHandler() {
@Override
public void onSuccess(int statusCode, String response) {
LogUtils.v(TAG, statusCode + " " + response);
}
@Override
public void onFailure(int statusCode, String error_msg) {
LogUtils.v(TAG, statusCode + " " + error_msg);
}
});複製程式碼
2.1.3 上傳檔案
Map<String, String> params = new HashMap<String, String>();
params.put("name", "tsy");
Map<String, File> files = new HashMap<String, File>();
File file = new File(Environment.getExternalStorageDirectory() + "/com.ci123.service.splashandroid/splash/1.png");
files.put("avatar", file);
MyOkHttp.get().upload(this, "http://192.168.3.1/test_post.php", params, files, new GsonResponseHandler<BB>() {
@Override
public void onFailure(int statusCode, String error_msg) {
LogUtils.v(TAG, statusCode + " " + error_msg);
}
@Override
public void onSuccess(int statusCode, BB response) {
LogUtils.v(TAG, statusCode + " " + response.ret);
}
@Override
public void onProgress(long currentBytes, long totalBytes) {
LogUtils.v(TAG, currentBytes + "/" + totalBytes);
}
});複製程式碼
2.1.4 下載檔案
MyOkHttp.get().download(this, "http://192.168.3.1/output_tmp.jpg",
Environment.getExternalStorageDirectory() + "/com.tsy.splashandroid/", "1.jpg",
new DownloadResponseHandler() {
@Override
public void onFinish(File download_file) {
LogUtils.v(TAG, "onFinish:" + download_file.getPath());
}
@Override
public void onProgress(long currentBytes, long totalBytes) {
LogUtils.v(TAG, currentBytes + "/" + totalBytes);
}
@Override
public void onFailure(String error_msg) {
LogUtils.v(TAG, error_msg);
}
});複製程式碼
2.1.5 取消請求(建議放在BaseActivity,BaseFragment的onDestroy中)
MyOkHttp.get().cancel(this);複製程式碼
2.1.6 返回格式
post,get,upload3個介面可以選擇返回格式為普通Json還是Gson
-
普通json
回撥繼承JsonResponseHandler,例如POST請求的例子 -
gson
回撥繼承GsonResponseHandler,並設定泛型T,例如Upload請求的例子 -
raw原始資料
回撥繼承RawResponseHandler,例如GET請求例子
2.2 原始碼解析
原始碼整合在了BaseAndroidProject中作為網路底層模組,以module方式封裝。其他專案可以直接module拿過來引入專案即可使用。
BaseAndroidProject的Github地址:
github.com/tsy12321/Ba…
原始碼API入口在MyOkhttp檔案中。POST請求和GET請求的實現很簡單。在這我主要說明如何封裝gson response和上傳下載的進度監聽。
2.2.1 gson返回封裝
gson最後封裝成了如下的使用形式:
MyOkHttp.get().post(this, "http://192.168.3.1/test_okhttp.php", params, new GsonResponseHandler<BB>() {
@Override
public void onFailure(int statusCode, String error_msg) {
LogUtils.v(TAG, statusCode + " " + error_msg);
}
@Override
public void onSuccess(int statusCode, BB response) {
LogUtils.v(TAG, statusCode + " " + response.ret);
}
});複製程式碼
gson response與普通json返回不同的是,在GsonResponseHandler的建構函式中使用反射機制動態獲取到了本身的泛型型別,然後將該泛型型別轉化為了Gson可以使用的Type儲存起來。這樣在結果回撥時就可以使用該Type轉為Gson。
public abstract class GsonResponseHandler<T> implements IResponseHandler {
Type mType;
public GsonResponseHandler() {
Type myclass = getClass().getGenericSuperclass(); //反射獲取帶泛型的class
if (myclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameter = (ParameterizedType) myclass; //獲取所有泛型
mType = $Gson$Types.canonicalize(parameter.getActualTypeArguments()[0]); //將泛型轉為type
}
public final Type getType() {
return mType;
}
public abstract void onSuccess(int statusCode, T response);
@Override
public void onProgress(long currentBytes, long totalBytes) {
}
}複製程式碼
然後在okhttp獲得到response後,判斷到responseHandler是gson,就將結果轉為gson格式。
if(mResponseHandler instanceof JsonResponseHandler) {
...
} else if(mResponseHandler instanceof GsonResponseHandler) {
mHandler.post(new Runnable() {
@Override
public void run() {
try {
Gson gson = new Gson();
((GsonResponseHandler)mResponseHandler).onSuccess(response.code(),
gson.fromJson(response_body, ((GsonResponseHandler)mResponseHandler).getType()));
} catch (Exception e) {
LogUtils.e("onResponse fail parse gson, body=" + response_body, e);
mResponseHandler.onFailure(response.code(), "fail parse gson, body=" + response_body);
}
}
});
}複製程式碼
2.2.2 上傳和下載的監聽進度
該部分參考了趙凱強的-開源專案OkHttpPlus 裡面說明的比較清楚。大概的原理就是使用okio分別重寫requestbody和responsebody,在body中設定進度監聽返回。just so so。詳細原理可以直接跳轉部落格進行學習啊,在這就不重新造輪子了。
3 結尾
最終,okhttp被我封裝為了一個module,在這個module中就會引入gson和okhttp了,所以不把它匯出為jar包。以後的網路底層庫就用這個module啦!
更多文章關注我的公眾號