本文簡述了爲何選擇okhttp做爲本身的項目網絡庫,和如何二次封裝爲module便於使用php
注:進階版MyOkHttp見文章:java
juejin.im/post/59c4be…android
該系列文章會不斷更新Android項目開發中一些好的架構和小技巧git
系列一 Android架構系列-基於MVP建立適合本身的架構
系列二 Android架構系列-如何優美的寫Intent
系列三 Android架構系列-開發規範
系列四 Android架構系列-封裝本身的okhttp
系列五 Android架構系列-MVP架構的實際應用github
原本項目的網絡庫選擇的搭配是最流行的retrofit+okhttp+gson.以下圖版本庫裏還有記錄。json
But!後來遇到了這樣的問題:服務端提供的API沒法遵循Restful的API格式,並且不一樣模塊因爲分服務開發的,也不能保證格式一致。致使API接口層的實現十分牽強。最終api層的編寫不能專一於業務,拔苗助長。(最起碼如今的服務端還不適合與retrofit的使用)api
最後決定放棄使用retrofit,使用本身二次封裝的okhttp。網絡
封裝過程當中參考了:架構
hongyang的Android OkHttp徹底解析 是時候來了解OkHttp了ide
趙凱強的開源項目OkHttpPlus
先說封裝好的okhttp+gson如何使用。(封裝了POST請求,GET請求,上傳文件,下載文件,取消請求和Gson轉換等功能)
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);
}
});複製代碼
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);
}
});複製代碼
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);
}
});複製代碼
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);
}
});複製代碼
MyOkHttp.get().cancel(this);複製代碼
post,get,upload3個接口能夠選擇返回格式爲普通Json仍是Gson
普通json
回調繼承JsonResponseHandler,例如POST請求的例子
gson
回調繼承GsonResponseHandler,並設置泛型T,例如Upload請求的例子
raw原始數據
回調繼承RawResponseHandler,例如GET請求例子
源碼集成在了BaseAndroidProject中做爲網絡底層模塊,以module方式封裝。其餘項目能夠直接module拿過來引入項目便可使用。
BaseAndroidProject的Github地址:
github.com/tsy12321/Ba…
源碼API入口在MyOkhttp文件中。POST請求和GET請求的實現很簡單。在這我主要說明如何封裝gson response和上傳下載的進度監聽。
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);
}
}
});
}複製代碼
該部分參考了趙凱強的-開源項目OkHttpPlus 裏面說明的比較清楚。大概的原理就是使用okio分別重寫requestbody和responsebody,在body中設置進度監聽返回。just so so。詳細原理能夠直接跳轉博客進行學習啊,在這就不從新造輪子了。
最終,okhttp被我封裝爲了一個module,在這個module中就會引入gson和okhttp了,因此不把它導出爲jar包。之後的網絡底層庫就用這個module啦!
更多文章關注個人公衆號