RxRetrofit - 終極封裝 - 深刻淺出 & 擴展 String

背景

在以前的封裝1-5RxRetrofit-深刻淺出-終極封裝中咱們都是經過傳統的GsonConverterFactory自動解析,這樣作確實很方便,用戶能直接獲取返回的對象,不用關心具體的轉換,可是:這隨之而來有不少的缺陷(雖然官網推薦這樣使用);html

好比:沒法使用其餘第三發轉換框架;泛型沒法中間傳遞,封裝沒法統一處理緩存結果;回調信息沒法統一處理;服務器返回格式不嚴謹null解析異常..........
因此咱們在享受它遍歷的同時也被迫的要限制作不少的處理,限制咱們的擴展!java

本章就介紹如何放棄GsonConverterFactory,直接返回String,擴展咱們的封裝!(封裝的總體思想和以前的封裝同樣,因此不會有大的改動!)git

無須擔憂,本篇封裝單獨做爲一個項目和以前封裝分開,便於你們選擇!github


效果

這裏寫圖片描述


功能

徹底具有和以前封裝同樣的功能,這裏改用fastjson處理數據庫

1.Retrofit+Rxjava+okhttp基本使用方法

    2.統一處理請求數據格式

    3.統一的ProgressDialog和回調Subscriber處理

    4.取消http請求

    5.預處理http請求

    6.返回數據的統一判斷

    7.失敗後的retry處理

    8.RxLifecycle管理生命週期,防止泄露

    9.文件上傳下載(支持多文件,斷點續傳)

    10.Cache數據持久化和數據庫(greenDao)兩種緩存機制

    11.一對多回調接口處理複製代碼

對比

話說沒有比較就沒有進步,因此你們比較下先後封裝的各自的優缺點,自行選擇合適本身的方案!json

使用

Gson方案:api

// 完美封裝簡化版
    private void simpleDo() {
        SubjectPostApi postEntity = new SubjectPostApi(simpleOnNextListener,this);
        postEntity.setAll(true);
        HttpManager manager = HttpManager.getInstance();
        manager.doHttpDeal(postEntity);
    }

    // 回調一一對應
    HttpOnNextListener simpleOnNextListener = new HttpOnNextListener<List<SubjectResulte>>() {
        @Override
        public void onNext(List<SubjectResulte> subjects) {
            tvMsg.setText("網絡返回:\n" + subjects.toString());
        }

        @Override
        public void onCacheNext(String cache) {
            /*緩存回調*/
            Gson gson=new Gson();
            java.lang.reflect.Type type = new TypeToken<BaseResultEntity<List<SubjectResulte>>>() {}.getType();
            BaseResultEntity resultEntity= gson.fromJson(cache, type);
            tvMsg.setText("緩存返回:\n"+resultEntity.getData().toString() );
        }

        /*用戶主動調用,默認是不須要覆寫該方法*/
        @Override
        public void onError(Throwable e) {
            super.onError(e);
            tvMsg.setText("失敗:\n" + e.toString());
        }

        /*用戶主動調用,默認是不須要覆寫該方法*/
        @Override
        public void onCancel() {
            super.onCancel();
            tvMsg.setText("取消請求");
        }
    };複製代碼

String方案

// 完美封裝簡化版
    private void simpleDo() {
         /*初始化數據*/
        manager=new HttpManager(this,this);
        postEntity = new SubjectPostApi();
        postEntity.setAll(true);
        manager.doHttpDeal(postEntity);
    }



    @Override
    public void onNext(String resulte, String mothead) {
        /*post返回處理*/
        if(mothead.equals(postEntity.getMothed())){
            List<SubjectResulte>  subjectResulte= JSONObject.parseArray(resulte,SubjectResulte.class);
            tvMsg.setText("post返回:\n"+subjectResulte.toString() );
        }

        /*上傳返回處理*/
        if(mothead.equals(uplaodApi.getMothed())){
            UploadResulte uploadResulte=JSONObject.parseObject(resulte,UploadResulte.class);
            tvMsg.setText("上傳成功返回:\n"+uploadResulte.getHeadImgUrl());
            Glide.with(MainActivity.this).load(uploadResulte.getHeadImgUrl()).skipMemoryCache(true).into(img);
        }
    }

    @Override
    public void onError(Throwable e) {
        tvMsg.setText("失敗:\n" + e.toString());
    }複製代碼

Gson封裝方案中,咱們採用了一一對應的返回原則,將因此的請求數據參數都放入到baseApi中,返回放入對應的HttpOnNextListener
String方案中咱們則採用一對多原則,將回調和請求分開處理,公用一個回調,經過回調中的mothead來區分不一樣的接口,因此上述能夠看見後者裏面其實還處理了上傳的回調處理!緩存

從封裝的用法上能夠看出:
優勢:String封裝更加的靈活,能夠指定Gson轉換的第三方工具,統一的結果返回處理代碼更加的少(能夠完美解決緩存沒法統一回調的問題);服務器

一樣也有缺點:String封裝沒法自動解析結果類型,須要手動處理(我反而以爲這也是它的優勢,更加的靈活,我的見解)cookie


實現

因爲是基於以前的封裝修改,因此前提是瞭解以前的封裝之後才能徹底瞭解一下的修改實現思路Rxjava+ReTrofit+okHttp深刻淺出-終極封裝

1.替換GsonConverterFactory

因爲GsonConverterFactory會自動解析Gson,替換成直接返回StringScalarsConverterFactory

導入相關包(爲了區別-使用fastjson可自由擴展)

compile 'com.squareup.retrofit2:converter-scalars:+'
    compile 'com.alibaba:fastjson:+'複製代碼

替換

compile 'com.squareup.retrofit2:converter-gson:+'
 compile 'com.google.code.gson:gson:+'複製代碼

2.修改retrofit構建

ScalarsConverterFactory替換GsonConverterFactory

/*建立retrofit對象*/
        Retrofit retrofit = new Retrofit.Builder()
                .client(builder.build())
                .addConverterFactory(ScalarsConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(basePar.getBaseUrl())
                .build();
        HttpService  httpService = retrofit.create(HttpService.class);複製代碼

替換

/*建立retrofit對象*/
        Retrofit retrofit = new Retrofit.Builder()
                .client(builder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(basePar.getBaseUrl())
                .build();
        HttpService  httpService = retrofit.create(HttpService.class);複製代碼

3.修改緩存記錄位置

因爲以前是爲了防止gson重複解析,將緩存放入到自定義CookieInterceptor中;既然如今不須要自動轉換,直接返回String,因此直接將緩存數據處理放入到ProgressSubscriberonNext中處理;

3.1:去掉CookieInterceptor

//手動建立一個OkHttpClient並設置超時時間緩存等設置
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.addInterceptor(new CacheInterceptor());
        builder.addNetworkInterceptor(new CacheInterceptor());複製代碼

替換

//手動建立一個OkHttpClient並設置超時時間緩存等設置
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.addNetworkInterceptor(new CacheInterceptor());
        builder.addInterceptor(new CookieInterceptor(basePar.isCache()));複製代碼

3.2:實現緩存處理

onNext中實現緩存處理

/** * 將onNext方法中的返回結果交給Activity或Fragment本身處理 * * @param t 建立Subscriber時的泛型類型 */
    @Override
    public void onNext(T t) {
         /*緩存處理*/
        if(api.isCache()){
            CookieResulte resulte= CookieDbUtil.getInstance().queryCookieBy(api.getUrl());
            long time=System.currentTimeMillis();
            /*保存和更新本地數據*/
            if(resulte==null){
                resulte  =new CookieResulte(api.getUrl(),t.toString(),time);
                CookieDbUtil.getInstance().saveCookie(resulte);
            }else{
                resulte.setResulte(t.toString());
                resulte.setTime(time);
                CookieDbUtil.getInstance().updateCookie(resulte);
            }
        }
        if (mSubscriberOnNextListener.get() != null) {
            mSubscriberOnNextListener.get().onNext((String) t,api.getMothed());
        }
    }複製代碼

4.修改回調接口信息

因爲如今經過String直接返回,因此能夠將成功回調和緩存回調合並處理;另外一方面沒有了泛型的限制,在回調時能夠經過接口請求參數實現一對多回調處理;

/** * 成功回調處理 * Created by WZG on 2016/7/16. */
public interface HttpOnNextListener {
    /** * 成功後回調方法 * @param resulte * @param method */
   void onNext(String resulte,String method);

    /** * 失敗或者錯誤方法 * 主動調用,更加靈活 * @param e */
   void onError(Throwable e);
}複製代碼

5.修改BaseApi

因爲取消了泛型返回的機制,因此在Func1判斷時須要手動轉換數據;這裏示例fastjeson用法轉換

@Override
    public String call(T httpResult) {
        BaseResultEntity baseResulte= JSONObject.parseObject(httpResult.toString(),BaseResultEntity.class);
        if (baseResulte.getRet() == 0) {
            throw new HttpTimeException(baseResulte.getMsg());
        }
        return baseResulte.getData();
    }複製代碼

替換

@Override
    public T call(BaseResultEntity<T> httpResult) {
        if (httpResult.getRet() == 0) {
            throw new HttpTimeException(httpResult.getMsg());
        }
        return httpResult.getData();
    }複製代碼

6.修改結果基礎類BaseResultEntity

將泛型數據改爲String數據類型

/** * 回調信息統一封裝類 * Created by WZG on 2016/7/16. */
public class BaseResultEntity {
    // 判斷標示
    private int ret;
    // 提示信息
    private String msg;
    //顯示數據(用戶須要關心的數據)
    private String data;
 }複製代碼

替換

/** * 回調信息統一封裝類 * Created by WZG on 2016/7/16. */
public class BaseResultEntity<T> {
    // 判斷標示
    private int ret;
    // 提示信息
    private String msg;
    //顯示數據(用戶須要關心的數據)
    private T data;
 }複製代碼

7.合併緩存和成功回到返回處理

因爲取消泛型,緩存和成統一處理因此須要修改

/** * 訂閱開始時調用 * 顯示ProgressDialog */
    @Override
    public void onStart() {
        showProgressDialog();
        /*緩存而且有網*/
        if(api.isCache()&& AppUtil.isNetworkAvailable(MyApplication.app)){
             /*獲取緩存數據*/
            CookieResulte cookieResulte= CookieDbUtil.getInstance().queryCookieBy(api.getUrl());
            if(cookieResulte!=null){
                long time= (System.currentTimeMillis()-cookieResulte.getTime())/1000;
                if(time< api.getCookieNetWorkTime()){
                    if( mSubscriberOnNextListener.get()!=null){
                        mSubscriberOnNextListener.get().onNext(cookieResulte.getResulte(),api.getMothed());
                    }
                    onCompleted();
                    unsubscribe();
                }
            }
        }
    }複製代碼

替換

/** * 訂閱開始時調用 * 顯示ProgressDialog */
    @Override
    public void onStart() {
        showProgressDialog();
        /*緩存而且有網*/
        if(api.isCache()&& AppUtil.isNetworkAvailable(MyApplication.app)){
             /*獲取緩存數據*/
            CookieResulte cookieResulte= CookieDbUtil.getInstance().queryCookieBy(api.getUrl());
            if(cookieResulte!=null){
                long time= (System.currentTimeMillis()-cookieResulte.getTime())/1000;
                if(time< api.getCookieNetWorkTime()){
                    if( mSubscriberOnNextListener.get()!=null){
                        mSubscriberOnNextListener.get().onCacheNext(cookieResulte.getResulte());
                    }
                    onCompleted();
                    unsubscribe();
                }
            }
        }
    }複製代碼

8.修改一對多回調處理

沒有了泛型,能夠修改HttpManager,採用動態建立,動態回調的方法解決多嵌套耦合的問題
**

8.1去掉默認構造傳參

public BaseApi(HttpOnNextListener listener, RxAppCompatActivity rxAppCompatActivity) {
        setListener(listener);
        setRxAppCompatActivity(rxAppCompatActivity);
        setShowProgress(true);
        setCache(true);
    }複製代碼

8.2:添加HttpManager動態傳參

/** * http交互處理類 * Created by WZG on 2016/7/16. */
public class HttpManager {
    /*弱引用對象*/
    private SoftReference<HttpOnNextListener>  onNextListener;
    private SoftReference<RxAppCompatActivity> appCompatActivity;

    public HttpManager(HttpOnNextListener onNextListener, RxAppCompatActivity appCompatActivity) {
        this.onNextListener=new SoftReference(onNextListener);
        this.appCompatActivity=new SoftReference(appCompatActivity);
    }
    *******************
    *******************
}複製代碼

8.3:經過method動態判斷接口返回

public class MainActivity extends RxAppCompatActivity implements HttpOnNextListener{
    @Override
    public void onNext(String resulte, String method) {
        /*post返回處理*/
        if(method.equals(postEntity.getMothed())){
           *******
        }

        /*上傳返回處理*/
        if(method.equals(uplaodApi.getMothed())){
           *********
        }
    }

    @Override
    public void onError(Throwable e) {
        tvMsg.setText("失敗:\n" + e.toString());
    }
 }複製代碼

大功告成!


下載模塊

因爲下載模塊是獨立存在,因此基本沒有修改,惟一修改的地方就是將HttpDownManager中的GsonConverterFactory替換成ScalarsConverterFactory便可!


總結

經過自定義String類型的返回處理方式,有效的解決了以前Gson自動轉換的問題

  • 1.一對一返回問題(代碼量多)

  • 2.緩存回調沒法和成功統一處理

  • 3.沒法指定gson轉換第三方庫

  • 4.回調監聽的多嵌套(耦合度大)

  • 5.解決服務器數據null異常

注意:這裏只是給你們提供了一個不一樣的解決方案,Gson自動解析返回的方案也是有它的優勢,能夠大大的減小開發的工做量,優缺點也很明顯;孰好孰壞自行判斷,自行選擇適合本身的方案(我的偏向後者String返回,比較靈活)


終極封裝專欄

RxJava+Retrofit+OkHttp深刻淺出-終極封裝專欄)


源碼

源碼傳送門-String變種方案-Github

源碼傳送門-Gson方案-Github


建議

若是你對這套封裝有任何的問題和建議歡迎加入QQ羣告訴我!

相關文章
相關標籤/搜索