天天看點

RxJava+Retrofit+OkHttp深入淺出-終極封裝二(網絡請求)

背景:

CSDN

部落格釋出了一系列的

RxJava+Retrofit+OkHttp

深入淺出-終極封裝 之前發出後收到很多朋友的關注,原本隻是自己學習後的一些經驗總結,但是有同學運用到實戰當中,這讓我很惶恐,所有後續一直更新了很多次版本,有些地方難免有所變動導緻之前的部落格有所出入,正好最近受到掘金邀請内測部落格,是以決定重新寫一版,按照最後疊代完成的封裝詳細的講述一遍,歡迎大家關注!

注意:由于本章的特殊性,後續文章比較長而且複雜,涉及内容也很多,是以大家準備好茶水,前方高能預警。

RxJava

+

Retrofit

+

OkHttp

深入淺出-終極封裝

封裝成果

封裝完以後,具有如下功能:

.Retrofit+Rxjava+okhttp基本使用方法
    .統一處理請求資料格式
    .統一的ProgressDialog和回調Subscriber處理
    .取消http請求
    .預處理http請求
    .傳回資料的統一判斷
    .失敗後的retry封裝處理
    .RxLifecycle管理生命周期,防止洩露
           

實作效果:

RxJava+Retrofit+OkHttp深入淺出-終極封裝二(網絡請求)

具體使用

封裝後http請求代碼如下

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

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

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

是不是很簡單?你可能說這還簡單,好咱們對比一下正常使用

Retrofit

的方法

/**  
    * Retrofit加入rxjava實作http請求  
    */  
   private void onButton9Click() {  
       //手動建立一個OkHttpClient并設定逾時時間  
       okhttp3.OkHttpClient.Builder builder = new OkHttpClient.Builder();  
       builder.connectTimeout(, TimeUnit.SECONDS);  

       Retrofit retrofit = new Retrofit.Builder()  
               .client(builder.build())  
               .addConverterFactory(GsonConverterFactory.create())  
               .addCallAdapterFactory(RxJavaCallAdapterFactory.create())  
               .baseUrl(HttpManager.BASE_URL)  
               .build();  

/        加載框  
       final ProgressDialog pd = new ProgressDialog(this);  

       HttpService apiService = retrofit.create(HttpService.class);  
       Observable<RetrofitEntity> observable = apiService.getAllVedioBy(true);  
       observable.subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())  
               .subscribe(  
                       new Subscriber<RetrofitEntity>() {  
                           @Override  
                           public void onCompleted() {  
                               if (pd != null && pd.isShowing()) {  
                                   pd.dismiss();  
                               }  
                           }  

                           @Override  
                           public void onError(Throwable e) {  
                               if (pd != null && pd.isShowing()) {  
                                   pd.dismiss();  
                               }  
                           }  

                           @Override  
                           public void onNext(RetrofitEntity retrofitEntity) {  
                               tvMsg.setText("無封裝:\n" + retrofitEntity.getData().toString());  
                           }  

                           @Override  
                           public void onStart() {  
                               super.onStart();  
                               pd.show();  
                           }  
                       }  

               );  
   }
           

可能你發現确是代碼有點多,但是更加可怕的是,如果你一個activity或者fragment中多次需要http請求,你需要多次重複的寫回調處理(一個回到就有4個方法呀!!!!反正我是忍受不了),而且以上處理還沒有做過多的判斷和錯誤校驗就如此複雜!~好了介紹完了,開始咱們的優化之路吧!

項目結構:

RxJava+Retrofit+OkHttp深入淺出-終極封裝二(網絡請求)

RxJava

如果你對

RxJava

不了解,好吧騷年趕快學學吧,不然真會

out

了,下面給出部落客當初學習

RxJava

的一些資源:

  • 扔物線的金典RxJava
  • RxJava進階一
  • RxJava進階二
  • RxJava進階三
  • RxJava進階四

Retrofit

咱家今天的主角來了,咱們也深入淺出一下了解下

Retrofit

使用,前方高能,如果你是深度

Retrofit

選手請直接跳過本節!!!

1.首先確定在AndroidManifest.xml中請求了網絡權限

<uses-permission android:name="android.permission.INTERNET"/>
           

2.在app/build.gradle添加引用

/*rx-android-java*/
    compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
    compile 'com.trello:rxlifecycle:1.0'
    compile 'com.trello:rxlifecycle-components:1.0'
    /*rotrofit*/
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:2.0.0'
    compile 'com.google.code.gson:gson:2.8.0'
           

3.常用注解

這裡介紹一些常用的注解的使用

  • @Query

    @QueryMap

    :用

    于Http Get

    請求傳遞參數
  • @Field

    :用于

    Post

    方式傳遞參數,需要在請求接口方法上添加

    @FormUrlEncoded

    ,即以表單的方式傳遞參數
  • @Body

    :用于

    Post

    ,根據轉換方式将執行個體對象轉化為對應字元串傳遞參數.比如

    Retrofit

    添加

    GsonConverterFactory

    則是将

    body

    轉化為

    gson

    字元串進行傳遞
  • @Path

    :用于

    URL

    上占位符
  • @Part

    :配合

    @Multipart

    使用,一般用于檔案上傳
  • @Header

    :添加

    http header

  • @Headers

    :跟

    @Header

    作用一樣,隻是使用方式不一樣,

    @Header

    是作為請求方法的參數傳入,

    @Headers

    是以固定方式直接添加到請求方法上

ReTrofit

基本使用:

首先給定一個測試接口文檔,後面的部落格中我們都是用這個接口調試

/**  
 * @api    videoLink    50音圖視訊連結  
 * @url    http://www.izaodao.com/Api/AppFiftyToneGraph/videoLink  
 * @method post  
 * @param  once_no bool(選填,ture無連結) 一次性擷取下載下傳位址  
 * @return json array(  
 * ret:1成功,2失敗  
 * msg:資訊  
 * data:{  
 *       name:視訊名稱  
 *       title:标題  
 * }  
 )
           

1.初始化retrofit

要向一個api發送我們的網絡請求 ,我們需要使用

Retrofit builder

類并指定

service

base URL

(通常情況下就是域名)。

String BASE_URL = " http://www.izaodao.com/Api/"  
    Retrofit retrofit = new Retrofit.Builder()  
            .baseUrl(BASE_URL)  
            .addConverterFactory(GsonConverterFactory.create())  
            .build();
           

2.設定接口

service

注意到每個

endpoint

 都指定了一個關于

HTTP

(

GET

POST

, 等等。) 方法的注解以及用于分發網絡調用的方法。而且這些方法的參數也可以有特殊的注解。

/**  
 * 接口位址  
 * Created by WZG on 2016/7/16.  
 */  
public interface MyApiEndpointInterface {  
    @POST("AppFiftyToneGraph/videoLink")  
    Call<RetrofitEntity> getAllVedio(@Body boolean once_no)             
}
           

3.得到

call

然後同步處理處理回調:

MyApiEndpointInterface apiService = retrofit.create(MyApiEndpointInterface.class);  
Call<RetrofitEntity> call = apiService.getAllVedio(true);  
call.enqueue(new Callback<RetrofitEntity>() {  
    @Override  
    public void onResponse(Response<RetrofitEntity> response, Retrofit retrofit) {  
        RetrofitEntity entity = response.body();  
        Log.i("tag", "onResponse----->" + entity.getMsg());  
    }  

    @Override  
    public void onFailure(Throwable t) {  
        Log.i("tag", "onFailure----->" + t.toString());  

    }  
});
           

這就是簡單的

Retrofit

使用步驟,接下來我們結合RxJava講述

ReTrofit+Rxjava

基本使用

對比之前的

Retrofit

使用

1.在于我們需要修改

service

接口傳回資訊我們需要傳回一個

Observable

對象

@POST("AppFiftyToneGraph/videoLink")  
Observable<RetrofitEntity> getAllVedioBy(@Body boolean once_no);
           

2.然後初始化

Retrofit

需要添加對

Rxjava

的适配,注意一定要

retrofit2

才有這個功能哦

Retrofit retrofit = new Retrofit.Builder()  
                .client(builder.build())  
                .addConverterFactory(GsonConverterFactory.create())  
               .addCallAdapterFactory(RxJavaCallAdapterFactory.create())  
                .baseUrl(HttpManager.BASE_URL)  
                .build();
           

3.回調通過

RxJava

處理

HttpService apiService = retrofit.create(HttpService.class);  
       Observable<RetrofitEntity> observable = apiService.getAllVedioBy(true);  
       observable.subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())  
               .subscribe(  
                       new Subscriber<RetrofitEntity>() {  
                           @Override  
                           public void onCompleted() {  
                           }  

                           @Override  
                           public void onError(Throwable e) {                                
                           }  

                           @Override  
                           public void onNext(RetrofitEntity retrofitEntity) {  
                               tvMsg.setText("無封裝:\n" + retrofitEntity.getData().toString());  
                           }                            
                       }  

               );
           

簡單的

RxJava

集合

Retrofit

的使用就介紹完了,同樣的可以發現使用起來很多重複性的代碼,而且使用也不是那麼簡單,是以才有了下面的封裝

ReTrofit+Rxjava進階封裝之路

先來一張流程圖壓壓驚

RxJava+Retrofit+OkHttp深入淺出-終極封裝二(網絡請求)

請求資料封裝

1.參數

首先需要封裝的使我們的資料類,在資料類中需要封裝請求中用到的相關資料的設定,比如請求參數、方法、加載框顯示設定等等

public abstract class BaseApi<T> implements Func1<BaseResultEntity<T>, T> {
    //rx生命周期管理
    private SoftReference<RxAppCompatActivity> rxAppCompatActivity;
    /*回調*/
    private SoftReference<HttpOnNextListener> listener;
    /*是否能取消加載框*/
    private boolean cancel;
    /*是否顯示加載框*/
    private boolean showProgress;
    /*是否需要緩存處理*/
    private boolean cache;
    /*基礎url*/
    private  String baseUrl="http://www.izaodao.com/Api/";
    /*方法-如果需要緩存必須設定這個參數;不需要不用設置*/
    private String mothed;
    /*逾時時間-預設6秒*/
    private int connectionTime = ;
    /*有網情況下的本地緩存時間預設60秒*/
    private int cookieNetWorkTime=;
    /*無網絡的情況下本地緩存時間預設30天*/
    private int cookieNoNetWorkTime=***;
}
           

注釋很詳細,這裡不具體描述了,由于這裡是最後封裝完成以後的代碼,是以有些内容本章還會部分不會涉及,因為功能太多,還是按照一開始的部落格章節講解。

2.抽象

api

接口

/**
     * 設定參數
     *
     * @param retrofit
     * @return
     */
    public abstract Observable getObservable(Retrofit retrofit);
           

通過子類也即是我們的具體

api

接口,通過

getObservable

實作

service

中定義的接口方法,例如:

public class SubjectPostApi extends BaseApi {
     xxxxxxx
     xxxxxxx

 @Override
    public Observable getObservable(Retrofit retrofit) {
        HttpPostService service = retrofit.create(HttpPostService.class);
        return service.getAllVedioBys(isAll());
    }
}
           

通過傳入的

Retrofit

對象,可以随意切換挑選

Service

對象,得到定義的注解方法,初始完成以後傳回

Observable

對象。

3.結果判斷

這裡結合

RxJava

map

方法在伺服器傳回資料中,統一處理資料處理,是以

BaseApi<T> implements Func1<BaseResultEntity<T>, T>

,後邊結合結果處理連結起來使用

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

由于測試接口,也是目前我們公司接口都是有統一規則的,想必大家都有這樣的接口規則,是以才有這裡的統一判斷,規則如下:

* ret:成功,失敗  
 * msg:資訊  
 * data:{  
 *       name:視訊名稱  
 *       title:标題  
 * }
           

其實上面的接口文檔中就介紹了,統一先通過

ret

判斷,失敗顯示

msg

資訊,

data

是成功後的資料也就是使用者關心的資料,是以可封裝一個結果對象

BaseResultEntity

.

4.結果資料

/**
 * 回調資訊統一封裝類
 * Created by WZG on 2016/7/16.
 */
public class BaseResultEntity<T> {
    //  判斷标示
    private int ret;
    //    提示資訊
    private String msg;
    //顯示資料(使用者需要關心的資料)
    private T data;


    xxxxx  get-set  xxxxx
}
           

這裡結合

BaseApi

Func1

判斷,失敗直接抛出一個異常,交個

RxJava

onError

處理,成功則将使用者關心的資料傳給

Gson

解析傳回

5.泛型傳遞

BaseResultEntity<T>

中的泛型

T

也就是我們所關心的回調資料,同樣也是Gson最後解析傳回的資料,傳遞的過程根節點是通過定義

service

方法是給定的,例如:

public interface HttpPostService {
    @POST("AppFiftyToneGraph/videoLink")
    Call<RetrofitEntity> getAllVedio(@Body boolean once_no);
}
           

其中的

RetrofitEntity

就是使用者關心的資料類,通過泛型傳遞給最後的接口。

6.強調

很多兄弟通過QQ群回報給我說,使用一個接口需要寫一個對應的

api

類繼承

BaseApi

是不是很麻煩,我這裡強調一下,這樣封裝是為了将一個

Api

接口作為一個對象去封裝,個人覺得有必要封裝成一個類,在日後工程日益增加接口随着增加的同時,對象的做法更加有利于查找接口和修改接口有利于疊代。

操作類封裝

1初始對象

首先初始化一個單利友善

HttpManager

請求;這裡用了

volatile

的對象,不懂的同學可以參考我的另一篇部落格

你真的會寫單例嗎
private volatile static HttpManager INSTANCE;

    //構造方法私有
    private HttpManager() {
    }

    //擷取單例
    public static HttpManager getInstance() {
        if (INSTANCE == null) {
            synchronized (HttpManager.class) {
                if (INSTANCE == null) {
                    INSTANCE = new HttpManager();
                }
            }
        }
        return INSTANCE;
    }
           

2接口處理和回調處理:

/**
     * 處理http請求
     *
     * @param basePar 封裝的請求資料
     */
    public void doHttpDeal(BaseApi basePar) {
        //手動建立一個OkHttpClient并設定逾時時間緩存等設定
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(basePar.getConnectionTime(), TimeUnit.SECONDS);
        builder.addInterceptor(new CookieInterceptor(basePar.isCache()));

        /*建立retrofit對象*/
        Retrofit retrofit = new Retrofit.Builder()
                .client(builder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(basePar.getBaseUrl())
                .build();


        /*rx處理*/
        ProgressSubscriber subscriber = new ProgressSubscriber(basePar);
        Observable observable = basePar.getObservable(retrofit)
                /*失敗後的retry配置*/
                .retryWhen(new RetryWhenNetworkException())
                /*生命周期管理*/
                .compose(basePar.getRxAppCompatActivity().bindToLifecycle())
                /*http請求線程*/
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                /*回調線程*/
                .observeOn(AndroidSchedulers.mainThread())
                /*結果判斷*/
                .map(basePar);

        /*資料回調*/
        observable.subscribe(subscriber);
    }
           

首先通過

api

接口類

BaseApi

的實作類中資料初始化

OkHttpClient

Retrofit

對象,其中包含了

url

,逾時等,接着通過

BaseApi

的抽象方法

getObservable

得到

Observable

對象,得到

Observable

對象以後,我們就能随意的切換現成來處理,整個請求通過

compose

設定的

rxlifecycle

來管理生命周期,是以不會溢出和洩露無需任何擔心,最後再伺服器資料傳回時,通過

map

判斷結果,剔除錯誤資訊,成功以後傳回到自定義的

ProgressSubscriber

對象中,是以接下來封裝

ProgressSubscriber

對象。

ProgressSubscriber

封裝

ProgressSubscriber

其實是繼承于

Subscriber

,封裝的方法無非是對

Subscriber

的回調方法的封裝

  • onStart():開始
  • onCompleted():結束
  • onError(Throwable e):錯誤
  • onNext(T t):成功

1.請求加載框

http

請求都伴随着加載框的使用,是以這裡需要在

onStart()

使用前初始一個加載框,這裡簡單的用

ProgressDialog

代替

/**
 * 用于在Http請求開始時,自動顯示一個ProgressDialog
 * 在Http請求結束是,關閉ProgressDialog
 * 調用者自己對請求資料進行處理
 * Created by WZG on 2016/7/16.
 */
public class ProgressSubscriber<T> extends Subscriber<T> {
    /*是否彈框*/
    private boolean showPorgress = true;
    /* 軟引用回調接口*/
    private SoftReference<HttpOnNextListener> mSubscriberOnNextListener;
    /*軟引用反正記憶體洩露*/
    private SoftReference<RxAppCompatActivity> mActivity;
    /*加載框可自己定義*/
    private ProgressDialog pd;
    /*請求資料*/
    private BaseApi api;


    /**
     * 構造
     *
     * @param api
     */
    public ProgressSubscriber(BaseApi api) {
        this.api = api;
        this.mSubscriberOnNextListener = api.getListener();
        this.mActivity = new SoftReference<>(api.getRxAppCompatActivity());
        setShowPorgress(api.isShowProgress());
        if (api.isShowProgress()) {
            initProgressDialog(api.isCancel());
        }
    }


    /**
     * 初始化加載框
     */
    private void initProgressDialog(boolean cancel) {
        Context context = mActivity.get();
        if (pd == null && context != null) {
            pd = new ProgressDialog(context);
            pd.setCancelable(cancel);
            if (cancel) {
                pd.setOnCancelListener(new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialogInterface) {
                        onCancelProgress();
                    }
                });
            }
        }
    }


    /**
     * 顯示加載框
     */
    private void showProgressDialog() {
        if (!isShowPorgress()) return;
        Context context = mActivity.get();
        if (pd == null || context == null) return;
        if (!pd.isShowing()) {
            pd.show();
        }
    }


    /**
     * 隐藏
     */
    private void dismissProgressDialog() {
        if (!isShowPorgress()) return;
        if (pd != null && pd.isShowing()) {
            pd.dismiss();
        }
    }
}
           

由于

progress

的特殊性,需要指定

content

而且不能是

Application

是以這裡傳遞一個

RxAppCompatActivity

,而同時上面的

HttpManager

同樣需要,是以這裡統一還是按照

BaseApi

傳遞過來,使用軟引用的方式避免洩露。剩下的無非是初始化,顯示和關閉方法,可以詳細看代碼。

2.

onStart()

實作

onStart()

中需要調用加載框,然後這裡還有網絡緩存的邏輯,後面會單獨講解,現在先忽略它的存在。

/**
     * 訂閱開始時調用
     * 顯示ProgressDialog
     */
    @Override
    public void onStart() {
        showProgressDialog();
        /*緩存并且有網*/
        if (api.isCache() && AppUtil.isNetworkAvailable(RxRetrofitApp.getApplication())) {
             /*擷取緩存資料*/
            CookieResulte cookieResulte = CookieDbUtil.getInstance().queryCookieBy(api.getUrl());
            if (cookieResulte != null) {
                long time = (System.currentTimeMillis() - cookieResulte.getTime()) / ;
                if (time < api.getCookieNetWorkTime()) {
                    if (mSubscriberOnNextListener.get() != null) {
                        mSubscriberOnNextListener.get().onCacheNext(cookieResulte.getResulte());
                    }
                    onCompleted();
                    unsubscribe();
                }
            }
        }
    }
           

3.onCompleted()實作

/**
     * 完成,隐藏ProgressDialog
     */
    @Override
    public void onCompleted() {
        dismissProgressDialog();
    }
           

4.onError(Throwable e)實作

onError(Throwable e)

是對錯誤資訊的處理和緩存讀取的處理,後續會講解,先忽略。

/**
     * 對錯誤進行統一處理
     * 隐藏ProgressDialog
     *
     * @param e
     */
    @Override
    public void onError(Throwable e) {
        dismissProgressDialog();
        /*需要緩存并且本地有緩存才傳回*/
        if (api.isCache()) {
            Observable.just(api.getUrl()).subscribe(new Subscriber<String>() {
                @Override
                public void onCompleted() {

                }

                @Override
                public void onError(Throwable e) {
                    errorDo(e);
                }

                @Override
                public void onNext(String s) {
                    /*擷取緩存資料*/
                    CookieResulte cookieResulte = CookieDbUtil.getInstance().queryCookieBy(s);
                    if (cookieResulte == null) {
                        throw new HttpTimeException("網絡錯誤");
                    }
                    long time = (System.currentTimeMillis() - cookieResulte.getTime()) / ;
                    if (time < api.getCookieNoNetWorkTime()) {
                        if (mSubscriberOnNextListener.get() != null) {
                            mSubscriberOnNextListener.get().onCacheNext(cookieResulte.getResulte());
                        }
                    } else {
                        CookieDbUtil.getInstance().deleteCookie(cookieResulte);
                        throw new HttpTimeException("網絡錯誤");
                    }
                }
            });
        } else {
            errorDo(e);
        }
    }

    /*錯誤統一處理*/
    private void errorDo(Throwable e) {
        Context context = mActivity.get();
        if (context == null) return;
        if (e instanceof SocketTimeoutException) {
            Toast.makeText(context, "網絡中斷,請檢查您的網絡狀态", Toast.LENGTH_SHORT).show();
        } else if (e instanceof ConnectException) {
            Toast.makeText(context, "網絡中斷,請檢查您的網絡狀态", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(context, "錯誤" + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
        if (mSubscriberOnNextListener.get() != null) {
            mSubscriberOnNextListener.get().onError(e);
        }
    }
           

5.

onNext(T t)

實作

/**
     * 将onNext方法中的傳回結果交給Activity或Fragment自己處理
     *
     * @param t 建立Subscriber時的泛型類型
     */
    @Override
    public void onNext(T t) {
        if (mSubscriberOnNextListener.get() != null) {
            mSubscriberOnNextListener.get().onNext(t);
        }
    }
           

主要是是将得到的結果,通過自定義的接口傳回給

view

界面,其中的軟引用對象

mSubscriberOnNextListener

是自定義的接口回調類

HttpOnNextListener

.

6.

HttpOnNextListener

封裝

現在隻需關心

onNext(T t)

onError(Throwable e)

接口即可,回調的觸發點都是在上面的

ProgressSubscriber

中調用

/**
 * 成功回調處理
 * Created by WZG on 2016/7/16.
 */
public abstract class HttpOnNextListener<T> {
    /**
     * 成功後回調方法
     * @param t
     */
    public abstract void onNext(T t);

    /**
     * 緩存回調結果
     * @param string
     */
    public void onCacheNext(String string){

    }

    /**
     * 失敗或者錯誤方法
     * 主動調用,更加靈活
     * @param e
     */
    public  void onError(Throwable e){

    }

    /**
     * 取消回調
     */
    public void onCancel(){

    }
}
           

失敗後的

retry

處理

這裡你可能會問,

Retrofit

有自帶的

retry

處理呀,的确

Retrofit

有自帶的

retry

處理,但是有很多的局限,先看下使用

OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.retryOnConnectionFailure(true);
           

使用起來還是很友善,隻需要調用一個方法即可,但是它是不可控的,也就是沒有辦法設定

retry

時間次數,是以不太靈活,既然如此還不如自己封裝一下,因為用

RxJava

實作這個簡直小菜,無形中好像已經給

RxJava

打了廣告,中毒太深。

很簡單直接上代碼:

/**
 * retry條件
 * Created by WZG on 2016/10/17.
 */
public class RetryWhenNetworkException implements Func1<Observable<? extends Throwable>, Observable<?>> {
//    retry次數
    private int count = ;
//    延遲
    private long delay = ;
//    疊加延遲
    private long increaseDelay = ;

    public RetryWhenNetworkException() {

    }

    public RetryWhenNetworkException(int count, long delay) {
        this.count = count;
        this.delay = delay;
    }

    public RetryWhenNetworkException(int count, long delay, long increaseDelay) {
        this.count = count;
        this.delay = delay;
        this.increaseDelay = increaseDelay;
    }

    @Override
    public Observable<?> call(Observable<? extends Throwable> observable) {
        return observable
                .zipWith(Observable.range(, count + ), new Func2<Throwable, Integer, Wrapper>() {
                    @Override
                    public Wrapper call(Throwable throwable, Integer integer) {
                        return new Wrapper(throwable, integer);
                    }
                }).flatMap(new Func1<Wrapper, Observable<?>>() {
                    @Override
                    public Observable<?> call(Wrapper wrapper) {
                        if ((wrapper.throwable instanceof ConnectException
                                || wrapper.throwable instanceof SocketTimeoutException
                                || wrapper.throwable instanceof TimeoutException)
                                && wrapper.index < count + ) { //如果超出重試次數也抛出錯誤,否則預設是會進入onCompleted
                            return Observable.timer(delay + (wrapper.index - ) * increaseDelay, TimeUnit.MILLISECONDS);

                        }
                        return Observable.error(wrapper.throwable);
                    }
                });
    }

    private class Wrapper {
        private int index;
        private Throwable throwable;

        public Wrapper(Throwable throwable, int index) {
            this.index = index;
            this.throwable = throwable;
        }
    }
}
           

使用

到這裡,我們第一步封裝已經完成了,下面講解下如何使用,已經看明白的各位看官,估計早就看明白了使用方式,無非是建立一個

api

對象繼承

BaseApi

初始接口資訊,然後調用

HttpManager

對象的

doHttpDeal(BaseApi basePar)

方法,最後靜靜的等待回調類

HttpOnNextListener<T>

類傳回的

onNext(T t)

成功資料或者

onError(Throwable e)

資料。

其實代碼就是這樣:

api

接口對象

/**
 * 測試資料
 * Created by WZG on 2016/7/16.
 */
public class SubjectPostApi extends BaseApi {
//    接口需要傳入的參數 可自定義不同類型
    private boolean all;
    /*任何你先要傳遞的參數*/
//    String xxxxx;

    /**
     * 預設初始化需要給定回調和rx周期類
     * 可以額外設定請求設定加載框顯示,回調等(可擴充)
     * @param listener
     * @param rxAppCompatActivity
     */
    public SubjectPostApi(HttpOnNextListener listener, RxAppCompatActivity rxAppCompatActivity) {
        super(listener,rxAppCompatActivity);
        setShowProgress(true);
        setCancel(true);
        setCache(true);
        setMothed("AppFiftyToneGraph/videoLink");
        setCookieNetWorkTime();
        setCookieNoNetWorkTime(**);
    }

    public boolean isAll() {
        return all;
    }

    public void setAll(boolean all) {
        this.all = all;
    }

    @Override
    public Observable getObservable(Retrofit retrofit) {
        HttpPostService service = retrofit.create(HttpPostService.class);
        return service.getAllVedioBys(isAll());
    }
}
           

請求回調

//    完美封裝簡化版
    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("取消請求");
        }
    };
           

後續

到這裡,封裝功能中很多功能還沒涉及和講解,後續會陸續更新!

先給大家看看為師的完全體功能:

.Retrofit+Rxjava+okhttp基本使用方法
    .統一處理請求資料格式
    .統一的ProgressDialog和回調Subscriber處理
    .取消http請求
    .預處理http請求
    .傳回資料的統一判斷
    .失敗後的retry處理
    .RxLifecycle管理生命周期,防止洩露
    .檔案上傳下載下傳(支援多檔案,斷點續傳)
    .Cache資料持久化和資料庫(greenDao)兩種緩存機制
    .異常統一處理
           

來個圖壓壓驚:

RxJava+Retrofit+OkHttp深入淺出-終極封裝二(網絡請求)

迫不及待的小夥伴可以看這裡:

RxJava

+

Retrofit

+

OkHttp

深入淺出-終極封裝

但是其中有些後續優化疊代未及時更新,别生氣,我馬上補!

源碼:

RxRetrofit-終極封裝-深入淺出&網絡請求-GitHub

其實我還有一個兄弟版本-傳送門

我不會告訴你其實我還有個更加簡單的版本

建議

如果你對這套封裝有任何的問題和建議歡迎加入QQ群告訴我