1. 概述
上一期我們提了一下Volley,Okhttp,Retrofit到底應(yīng)該選哪一個?但是的確目前第三方的網(wǎng)絡(luò)框架比較多,也不知道再等個幾十年會出什么樣的,到時候我們可能還是要換,然而隨著版本的迭代這是一個很頭疼的事情,如果要更換更好的網(wǎng)絡(luò)框架成本就比較高了,今天我們來看一下怎么樣打造一套網(wǎng)絡(luò)框架引擎,一方面為了封裝,一方面為了方便切換網(wǎng)絡(luò)框架。
所有分享大綱:2017Android進(jìn)階之路與你同行
視頻講解地址:http://pan.baidu.com/s/1pKWuZrX
2. 套路分析
一般在開發(fā)中我們往往還要根據(jù)需求對第三方的網(wǎng)絡(luò)框架進(jìn)行封裝,如Okhttp、Volley、Retrofit等等。封裝是為了更符合我們的項目需求,方便調(diào)用,這一步可能少不了,那么我們只需要思考怎么樣才能做到任意切換網(wǎng)絡(luò)框架呢?如果能夠隨意切換最好。
其實我們請求的數(shù)據(jù)的時候基本是類似的無非就是獲取數(shù)據(jù)和顯示數(shù)據(jù),可問題就在于各大網(wǎng)絡(luò)框架的套路不一樣,所以只要解決這個問題就好了。那么這個時候我們只需要自己搞一個套路就好,我們Activity ->自己的套路 ->第三大網(wǎng)絡(luò)框架遵循我們的的套路->第三大網(wǎng)絡(luò)框架,但是這樣是不是會有問題呢?可能會有些許問題,畢竟不是直接的血緣關(guān)系,但是只要代碼好擴(kuò)展,隨著項目的推進(jìn)是很好完善的。
3. 實現(xiàn)
自定義一套規(guī)則,目前可以簡單點,當(dāng)然也可以根據(jù)項目需求稍微復(fù)雜點 IHttpEngine:
/**
* Created by Darren on 2017/03/01
* Email: 240336124@qq.com
* Description: 網(wǎng)絡(luò)引擎的規(guī)范
*/
public interface HttpEngine {
// post 提交
public void post(Context context, String url, Map<String, Object> params, HttpCallBack httpCallBack, boolean cache);
// get 提交
public void get(Context context, String url, Map<String, Object> params, HttpCallBack httpCallBack, boolean cache);
// 取消請求
// 下載文件
// 上傳文件
// https添加安全證書
}
定義自己的套路HttpUtils:
/**
* Created by Darren on 2017/03/01
* Email: 240336124@qq.com
* Description:
*/
public class HttpUtils {
// 上下文
private Context mContext;
// 網(wǎng)絡(luò)訪問引擎
private static HttpEngine mHttpEngine = new OkHttpEngine();
// 接口地址
private String mUrl;
// 請求參數(shù)
private Map<String, Object> mParams;
// get請求標(biāo)識
private final int GET_REQUEST = 0x0011;
// post請求標(biāo)識
private final int POST_REQUEST = 0x0022;
// 請求的方式
private int mRequestMethod = GET_REQUEST;
// 是否緩存
private boolean mCache = false;
// 切換引擎
public void exchangeEngine(HttpEngine httpEngine){
this.mHttpEngine = httpEngine;
}
// 可以在Application中配置HttpEngine
public static initEngine(HttpEngine httpEngine){
this.mHttpEngine = httpEngine;
}
private HttpUtils(Context context) {
this.mContext = context;
mParams = new HashMap<>();
}
public static HttpUtils with(Context context) {
return new HttpUtils(context);
}
public HttpUtils url(String url) {
mUrl = url;
return this;
}
// 執(zhí)行方法
public void execute(HttpCallBack httpCallBack) {
if (TextUtils.isEmpty(mUrl)) {
throw new NullPointerException("訪問路徑不能為空");
}
if (mRequestMethod == GET_REQUEST) {
get(mUrl, mParams, httpCallBack);
}
if (mRequestMethod == POST_REQUEST) {
post(mUrl, mParams, httpCallBack);
}
}
}
封裝一個簡單的事例OkhttpEnigne:
/**
* Created by Darren on 2017/03/01
* Email: 240336124@qq.com
* Description: OKHttp引擎
*/
public class OkHttpEngine implements HttpEngine {
private static OkHttpClient mOkHttpClient = new OkHttpClient();
@Override
public void post(final Context context, String url, Map<String, Object> params, final HttpCallBack httpCallBack, final boolean cache) {
// 省略部分代碼......
RequestBody requestBody = appendBody(params);
Request request = new Request.Builder()
.url(url)
.tag(context)
.post(requestBody)
.build();
mOkHttpClient.newCall(request).enqueue(
new Callback() {
@Override
public void onFailure(Call call, final IOException e) {
executeError(httpCallBack, e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String resultJson = response.body().string();
executeSuccessMethod(httpCallBack, resultJson);
// 緩存處理,下一期我們沒事干,自己手寫數(shù)據(jù)庫框架
}
}
);
}
/**
* 執(zhí)行成功的方法
**/
private void executeSuccessMethod(final HttpCallBack httpCallBack, final String resultJson) {
try {
HttpUtils.handler.post(new Runnable() {
@Override
public void run() {
httpCallBack.onSucceed(resultJson);
}
});
} catch (Exception e) {
executeError(httpCallBack, e);
e.printStackTrace();
}
}
/**
* 執(zhí)行失敗的方法
*/
private void executeError(final HttpCallBack httpCallBack, final Exception e) {
HttpUtils.handler.post(new Runnable() {
@Override
public void run() {
httpCallBack.onError(e);
}
});
}
@Override
public void get(Context context, String url, Map<String, Object> params, final HttpCallBack httpCallBack, boolean cache) {
// 省略部分代碼......
Request.Builder requestBuilder = new Request.Builder().url(url).tag(context);
Request request = requestBuilder.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
httpCallBack.onError(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String resultJson = response.body().string();
// 當(dāng)然有的時候還需要不同的些許處理
HttpUtils.handler.post(new Runnable() {
@Override
public void run() {
httpCallBack.onSucceed(result);
}
});
}
});
}
我們可以自己試試Retrofit的方式,這里我就不寫了,畢竟很多人對于Retrofit并不是特別了解。自己也希望可以從RxJava開始寫文章然后一步一步的上升到Retrofit。總之現(xiàn)在已經(jīng)有了一個默認(rèn)的OkHttpEngine了,如果需要配置或者切換我們需要去自定義一個引擎,然后切換到當(dāng)前引擎就可以了,我們看一下怎么使用:
HttpUtils.with(context)
.exchangeEngine(new RetrofitEngine());// 切換成Retrofit引擎
.url(UrlConstant.CITY_MAIN_PAGE) // 路徑
.addParam("city", mCurrentCity) // 添加參數(shù)
.cache(true) // 需要讀緩存
.post() // post提交
.execute(new HttpCallBack<CityFragmentEntity>() {
@Override
public void onError(Exception e) {
// 錯誤回調(diào)
}
@Override
public void onSucceed(CityFragmentEntity result) {
// result 返回的解析好的對象 可以直接操作不需要再Json解析
// 成功的回調(diào)
}
});
這其實也沒什么就是方便以后如果有了更好的第三方網(wǎng)絡(luò)框架那么我們可以在Application中配置引擎,也可以每次請求的時候指定不同的引擎,這其實就是面向接口編程而已,這里還遺留了一個問題就是數(shù)據(jù)緩存,下一期我們需要利用面向?qū)ο蟮乃枷胱约簞邮秩懸惶讛?shù)據(jù)庫封裝,我們得按需定制把數(shù)據(jù)庫寫到外部存儲卡中,還需要考慮數(shù)據(jù)庫加密,Query懶加載,Lucene輔助搜索等等等等,不光是為了造輪子而是為了更好的了解其他數(shù)據(jù)庫框架的原理。
所有分享大綱:2017Android進(jìn)階之路與你同行