Android架構系列-封裝本身的okhttp

本文簡述了爲何選擇okhttp做爲本身的項目網絡庫,和如何二次封裝爲module便於使用php

注:進階版MyOkHttp見文章:java

juejin.im/post/59c4be…android

0 Android架構系列文章

該系列文章會不斷更新Android項目開發中一些好的架構和小技巧git

系列一 Android架構系列-基於MVP建立適合本身的架構
系列二 Android架構系列-如何優美的寫Intent
系列三 Android架構系列-開發規範
系列四 Android架構系列-封裝本身的okhttp
系列五 Android架構系列-MVP架構的實際應用github

1 網絡庫的選擇和爲何放棄retrofit

原本項目的網絡庫選擇的搭配是最流行的retrofit+okhttp+gson.以下圖版本庫裏還有記錄。json

版本記錄
版本記錄

But!後來遇到了這樣的問題:服務端提供的API沒法遵循Restful的API格式,並且不一樣模塊因爲分服務開發的,也不能保證格式一致。致使API接口層的實現十分牽強。最終api層的編寫不能專一於業務,拔苗助長。(最起碼如今的服務端還不適合與retrofit的使用)api

最後決定放棄使用retrofit,使用本身二次封裝的okhttp。網絡

2 封裝使用okhttp

封裝過程當中參考了:架構

hongyang的Android OkHttp徹底解析 是時候來了解OkHttp了ide

趙凱強的開源項目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

  1. 普通json
    回調繼承JsonResponseHandler,例如POST請求的例子

  2. gson
    回調繼承GsonResponseHandler,並設置泛型T,例如Upload請求的例子

  3. 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啦!

目錄結構
目錄結構

更多文章關注個人公衆號

個人公衆號
個人公衆號
相關文章
相關標籤/搜索