Retrofit+rxjava的封裝

前言 基于以下參考進行改良封裝

一益老、接入前準備沿彭,將下面的依賴導入工程里面

    implementation 'io.reactivex.rxjava2:rxjava:2.1.0'
    // 必要rxjava2依賴
    implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
    // 必要rxandrroid依賴,切線程時需要用到
    implementation 'com.squareup.retrofit2:retrofit:2.3.0'
    // 必要retrofit依賴
    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
    // 必要依賴朦佩,和Rxjava結合必須用到并思,
    implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
    // 必要依賴,解析json字符所用
    
    //非必要依賴语稠, log依賴宋彼,如果需要打印OkHttpLog需要添加
    implementation 'com.squareup.okhttp3:logging-interceptor:3.8.1'
    //  gson轉換工廠
    implementation 'com.google.code.gson:gson:2.8.5'

二、Retrofit使用講解(網上許多參考故略)

三仙畦、工程結構圖

結構圖

四输涕、封裝流程

1. 進行Retrofit的封裝

  • 單例化Retrofit管理類
  • 初始化okhttp
  • 初始化retrofit
  private static final String CACHE_PATH = "httpCache";
    public static final long CACHE_SIZE = 1024 * 1024 * 100;
    public static final int TIMEOUT = 15; //超時時間
    private static volatile RetrofitManager mInstance;
    private Retrofit mRetrofit; //retorfit對象
    private OkHttpClient mOkhttpClient; //okhttp對象
    private ServerApi api; //生成接口類

   //單利化
    public static ServerApi getServerApi() {
        if (mInstance == null) {
            synchronized (RetrofitManager.class) {
                if (mInstance == null) {
                    mInstance = new RetrofitManager();
                }
            }
        }
        return mInstance.api;
    }


    /**
     * 構造器中初始化okhttp和retrofit
     */
    private RetrofitManager() {
        initOkhttp();//初始化okhttp 
        initRetrofit(); //初始retrofit
    }

    /**
     * 初始化retrofit
     */
    private void initRetrofit() {
        mRetrofit = new Retrofit.Builder()
                .baseUrl(CommonConstant.BASE_URL)
                .addConverterFactory(CustomGsonFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(mOkhttpClient)
                .build();
        api = mRetrofit.create(ServerApi.class);
    }

    /**
     * 初始化okhttp
     *
     * @return
     */
    private void initOkhttp() {
        //頭部參數攔截器
        HeaderParamsInterceptor commonParamsInterceptor = new HeaderParamsInterceptor();
        //日志參數攔截器
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        //關聯(lián)相應的攔截器
        interceptor.setLevel(CommonConstant.IS_DEBUG ? HttpLoggingInterceptor.Level.BODY : HttpLoggingInterceptor.Level.NONE);
        
        if (mOkhttpClient == null) {
            synchronized ((RetrofitManager.class)) {
                if (mOkhttpClient == null) {
                //增加緩存
                    Cache cache = new Cache(new File(MyApplication.getInstance().getCacheDir(), CACHE_PATH), CACHE_SIZE);
                    mOkhttpClient = new OkHttpClient.Builder()
                            .cache(cache)
                            .addInterceptor(interceptor)
                            .addInterceptor(commonParamsInterceptor)
//                            .retryOnConnectionFailure(true)
                            .connectTimeout(TIMEOUT, TimeUnit.SECONDS)
                            .build();
                }
            }
        }
    }


    /**
     * 用于創(chuàng)建相關類
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T create(Class<T> clazz) {
        if (mRetrofit != null) {
            return mRetrofit.create(clazz);
        }
        return null;
    }

2.根據要求封裝請求基類,響應基類慨畸,以及錯誤基類

  • 請求基類莱坎,由于我們請求會將請求參數放在請求體中,然后通過json數據傳給服務器
public class BaseRequest<T> {
    
    private T options;
    
    public T getOptions() {
        return options;
    }

    public void setOptions(T options) {
        this.options = options;
    }
}
  • 響應基類寸士,一般情況會有msg ,code,data這三個字段
public class BaseResponse<T> {
    @SerializedName(value = "code", alternate = "status")
    private int code; //返回碼
    private T data; //具體數據結果
    private String msg; //返回信息
    
    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

}
  • 錯誤基類檐什,可以根據實際情況來碴卧,我們接口的請求放在errorbody中,故可以這樣處理乃正,但是如果放在response中通過這就需要靈活處理這個數據住册,防止類造型錯誤。
public class FailureBody {
    private List data;
    @SerializedName(value = "code",alternate = "status")
    private int code;
    private String msg;
    

    public List getData() {
        return data;
    }

    public void setData(List data) {
        this.data = data;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

3.Observable的生成

  • 通過ObjectNetLoader這個類瓮具,簡化相應的線程切換
  • 通過繼承的NetDataLoader這個類生成相應的Observable對象
public class ObjectLoader {
    /**
     * 用于封裝相關
     * @param observable
     * @param <T>
     * @return
     */
    protected   <T> Observable<T> observer(Observable<T> observable){
        return observable.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }
}


/**
 * 用于對數據提前處理荧飞,同時也可用來對參數處理
 * 例如合并,map ,zip或者flateMap這樣可以將不符合自己參數的數據轉換為自己想請求的參數
 * 這一層是屬于module內名党,用于處理數據源区丑,供給presenter作為中間紐帶進行調用
 */
public class NetDataLoader extends ObjectLoader {
    private ServerApi api;
    private NetDataLoader() {
        api = RetrofitManager.getServerApi();
    }
    public static NetDataLoader loader;
    public static NetDataLoader get() {
        if (loader == null) {
            synchronized (NetDataLoader.class) {
                if (loader == null) {
                    loader = new NetDataLoader();
                }
            }
        }
        return loader;
    }
    /*******************************請求數據*****************************************/

    /************************************用戶**************************************/
    //用用戶信息登錄
    public Observable<BaseResponse<UserBean>> postUserLogin(ReqUserLogin bean) {
        return observer(api.postUserLogin(getRequestBody(bean))); //請求參數的初步處理
    }
    
    /***********************請求數據modle類*************************************/
    //用于對請求數據model修改為json數據
    private <T> BaseRequest getRequestBody(T data) {
        if (data == null)
            return null;
        BaseRequest<T> requestBody = new BaseRequest<>();
        requestBody.setOptions(data);
        return requestBody;
    }

}

  • observer的生成悍募,自定義Myobserver溪厘,既可以作為回調(供MVP中module回調接口)饰剥,也可以作為單獨使用。
/**
 * @param <T>
 */
public abstract class MyObserver<T> implements io.reactivex.Observer<BaseResponse<T>> {
    
    private Disposable d;

    @Override
    public void onSubscribe(Disposable d) {
        SubscriptionManager.newStance().add(d);//提前添加相應的Disposable
        this.d = d;
        onDisposable(d);
    }

    @Override
    public void onNext(BaseResponse<T> response) {
        if (response.getCode() == 200) {//通過200說明請求成功
            onSuccess(response);
        }
        SubscriptionManager.newStance().cancel(d);
    }

    @Override
    public void onError(Throwable e) {
        onFail(ExceptionHandle.handleException(e));
        SubscriptionManager.newStance().cancel(d);

    }

    @Override
    public void onComplete() {
        onCompleted();
        SubscriptionManager.newStance().cancel(d);

    }

    public abstract void onSuccess(BaseResponse<T> t);

    public abstract void onFail(ExceptionHandle.ResponseThrowable throwable);

    public abstract void onCompleted();

    public abstract void onDisposable(Disposable d);

}

4.Rxjava相關管理蒋歌,防止發(fā)生內存泄漏

  • 用于管理Rxjava帅掘,及時的取消訂閱,防止出現(xiàn)泄漏等情況(包括了Helper,以及管理類)
/**
 * 訂閱監(jiān)聽器幫助類
 * @param <T>
 */
public interface SubscriptionHelper<T> {
    void add(Disposable disposable); //添加
    void cancel(Disposable t); //取消
    void cancelAll(); //取消所有訂閱
}

public class SubscriptionManager implements SubscriptionHelper<Object> {
    public CompositeDisposable mDisposables;
    private static SubscriptionManager manager;

    private SubscriptionManager(){
        if(mDisposables == null){
            mDisposables = new CompositeDisposable();
        }
    }

    public static SubscriptionManager newStance(){
        if(manager == null){
            synchronized (SubscriptionManager.class){
                if(manager == null){
                    manager = new SubscriptionManager();
                }
            }
        }
        return manager;
    }


    @Override
    public void add(Disposable disposable) {
        if(disposable == null) return;
        mDisposables.add(disposable);
    }

    @Override
    public void cancel(Disposable t) {
        if(null == t) return;
        mDisposables.delete(t);
    }

    @Override
    public void cancelAll() {
        if(mDisposables != null && mDisposables.size() > 0){
            if(!mDisposables.isDisposed())
                mDisposables.dispose();
                mDisposables.clear();
        }
    }
}

5.異常處理類

  • 用于對錯誤和異常的同意處理堂油,通過在自定義observer中onError的回調中throwable的進行相關處理修档,從而統(tǒng)一回調給onFailure方法中,
public class ExceptionHandle {
    private static final int UNAUTHORIZED = 401; //用戶信息無效
    private static final int FORBIDDEN = 403;
    private static final int NOT_FOUND = 404;
    private static final int REQUEST_TIMEOUT = 408;
    private static final int INTERNAL_SERVER_ERROR = 500;
    private static final int BAD_GATEWAY = 502;
    private static final int SERVICE_UNAVAILABLE = 503;
    private static final int GATEWAY_TIMEOUT = 504;
    private static final int FAIL_QUEST = 406;//無法使用請求的內容特性來響應請求的網頁
    private static final int BAD_REQUEST = 400;
    private static ResponseBody body;

    public static ResponseThrowable handleException(Throwable e) {
        ResponseThrowable ex;
        if (e instanceof HttpException) {
            HttpException httpException = (HttpException) e;
            ex = new ResponseThrowable(e, ERROR.HTTP_ERROR);
            switch (httpException.code()) {
                case UNAUTHORIZED:
                    body = ((HttpException) e).response().errorBody();
                    try {
                        String message = body.string();
                        FailureBody body = GsonUtil.GsonToBean(message, FailureBody.class);
                        ex.code = body.getCode();
                        ex.message = body.getMsg();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                    break;
                case FORBIDDEN:
                    ex.message = "服務器已經理解請求府框,但是拒絕執(zhí)行它";
                    break;
                case NOT_FOUND:
                    body = ((HttpException) e).response().errorBody();
                    try {
                        String message = body.string();
                        FailureBody body = GsonUtil.GsonToBean(message, FailureBody.class);
                        ex.code = body.getCode();
                        ex.message = body.getMsg();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                    break;
                case REQUEST_TIMEOUT:
                    ex.message = "請求超時";
                    break;
                case GATEWAY_TIMEOUT:
                case INTERNAL_SERVER_ERROR:
                    ex.message = "服務器遇到了一個未曾預料的狀況吱窝,無法完成對請求的處理";
                    break;
                case BAD_REQUEST:
                    body = ((HttpException) e).response().errorBody();
                    try {
                        String message = body.string();
                        FailureBody failureBody = GsonUtil.GsonToBean(message, FailureBody.class);
                        ex.message = failureBody.getMsg();
                        ex.code = failureBody.getCode();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                    break;
                case BAD_GATEWAY:
                case SERVICE_UNAVAILABLE:
                case FAIL_QUEST:
                    body = ((HttpException) e).response().errorBody();
                    try { //用于處理相關信息
                        String message = body.string();
                        Gson gson = new Gson();
//                        ErrorBodyDTO globalExceptionDTO = gson.fromJson(message, ErrorBodyDTO.class);
//                        if (globalExceptionDTO.getErrMsg() != null) {
//                            ex.message = globalExceptionDTO.getErrMsg();
//                        } else {
//                            ex.message = "";
//                        }
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                    break;
                default:
                    ex.message = "網絡錯誤";
                    break;
            }
            return ex;
        } else if (e instanceof ServerException) {
            ServerException resultException = (ServerException) e;
            ex = new ResponseThrowable(resultException, resultException.code);
            ex.message = resultException.message;
            return ex;
        } else if (e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException) {
            ex = new ResponseThrowable(e, ERROR.PARSE_ERROR);
            ex.message = "解析錯誤";
            return ex;
        } else if (e instanceof ConnectException) {
            ex = new ResponseThrowable(e, ERROR.NETWORD_ERROR);
            ex.message = "連接失敗";
            return ex;
        } else if (e instanceof javax.net.ssl.SSLHandshakeException) {
            ex = new ResponseThrowable(e, ERROR.SSL_ERROR);
            ex.message = "證書驗證失敗";
            return ex;
        } else if (e instanceof java.net.SocketTimeoutException) {
            ex = new ResponseThrowable(e, ERROR.TIMEOUT_ERROR);
            //ex.message = "連接超時";
            ex.message = "當前網絡連接不順暢,請稍后再試迫靖!";
            return ex;
        } else if (e instanceof java.net.UnknownHostException) {
            ex = new ResponseThrowable(e, ERROR.TIMEOUT_ERROR);
            ex.message = "網絡中斷院峡,請檢查網絡狀態(tài)!";
            return ex;
        } else if (e instanceof javax.net.ssl.SSLException) {
            ex = new ResponseThrowable(e, ERROR.TIMEOUT_ERROR);
            ex.message = "網絡中斷系宜,請檢查網絡狀態(tài)照激!";
            return ex;
        } else if (e instanceof java.io.EOFException) {
            ex = new ResponseThrowable(e, ERROR.PARSE_EmptyERROR);
            ex.message = "1007";
            return ex;
        } else if (e instanceof java.lang.NullPointerException) {
            ex = new ResponseThrowable(e, ERROR.PARSE_EmptyERROR);
            ex.message = "數據為空,顯示失敗";
            return ex;
        } else {
            ex = new ResponseThrowable(e, ERROR.UNKNOWN);
            ex.message = "未知錯誤";
            return ex;
        }
    }


    /**
     * 約定異常
     */
    public class ERROR {
        /**
         * 未知錯誤
         */
        public static final int UNKNOWN = 1000;
        /**
         * 解析錯誤
         */
        public static final int PARSE_ERROR = 1001;
        /**
         * 解析no content錯誤
         */
        public static final int PARSE_EmptyERROR = 1007;
        /**
         * 網絡錯誤
         */
        public static final int NETWORD_ERROR = 1002;
        /**
         * 協(xié)議出錯
         */
        public static final int HTTP_ERROR = 1003;

        /**
         * 證書出錯
         */
        public static final int SSL_ERROR = 1005;

        /**
         * 連接超時
         */
        public static final int TIMEOUT_ERROR = 1006;

        public static final int LOGIN_ERROR = -1000;
        public static final int DATA_EMPTY = -2000;


    }

    public static class ResponseThrowable extends Exception {
        public int code;
        public String message;

        public ResponseThrowable(Throwable throwable, int code) {
            super(throwable);
            this.code = code;
        }

        public ResponseThrowable(String message, int code) {
            this.code = code;
            this.message = message;
        }
    }

    public class ServerException extends RuntimeException {
        public int code;
        public String message;

        public ServerException(int code, String message) {
            this.code = code;
            this.message = message;
        }
    }
}

5.使用方法

 NetDataLoader.get().postUserLogin(request).subscribe(new MyObserver<UserBean>() {
            @Override
            public void onSuccess(BaseResponse<UserBean> t) {
                
            }

            @Override
            public void onFail(ExceptionHandle.ResponseThrowable throwable) {

            }

            @Override
            public void onCompleted() {

            }

            @Override
            public void onDisposable(Disposable d) {

            }
        });

五盹牧、git傳送門

六俩垃、參考

1.Rxjava2+Retrofit2+MVP的網絡請求封裝

2.Android版&Kotlin版RxJava2+Retrofit2+OkHttp3的基礎、封裝和項目中的使用

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末汰寓,一起剝皮案震驚了整個濱河市口柳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌有滑,老刑警劉巖跃闹,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡辣卒,警方通過查閱死者的電腦和手機掷贾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進店門睛榄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荣茫,“玉大人,你說我怎么就攤上這事场靴》壤颍” “怎么了?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵旨剥,是天一觀的道長咧欣。 經常有香客問我,道長轨帜,這世上最難降的妖魔是什么魄咕? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮蚌父,結果婚禮上哮兰,老公的妹妹穿的比我還像新娘。我一直安慰自己苟弛,他們只是感情好喝滞,可當我...
    茶點故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著膏秫,像睡著了一般右遭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上缤削,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天窘哈,我揣著相機與錄音,去河邊找鬼亭敢。 笑死宵距,一個胖子當著我的面吹牛,可吹牛的內容都是我干的吨拗。 我是一名探鬼主播满哪,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼劝篷!你這毒婦竟也來了哨鸭?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤娇妓,失蹤者是張志新(化名)和其女友劉穎像鸡,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡只估,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年志群,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛔钙。...
    茶點故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡锌云,死狀恐怖,靈堂內的尸體忽然破棺而出吁脱,到底是詐尸還是另有隱情桑涎,我是刑警寧澤,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布兼贡,位于F島的核電站攻冷,受9級特大地震影響,放射性物質發(fā)生泄漏遍希。R本人自食惡果不足惜等曼,卻給世界環(huán)境...
    茶點故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望凿蒜。 院中可真熱鬧禁谦,春花似錦、人聲如沸篙程。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽虱饿。三九已至拥诡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間氮发,已是汗流浹背渴肉。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留爽冕,地道東北人仇祭。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像颈畸,于是被迫代替她去往敵國和親乌奇。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,728評論 2 351

推薦閱讀更多精彩內容