<轉(zhuǎn)>RxJava+Retrofit+OkHttp深入淺出-終極封裝七(異常處理)

背景

在前面Rxjava+ReTrofit+okHttp深入淺出-終極封裝專欄我們已經(jīng)全面的封裝了一套可以投入實(shí)戰(zhàn)的框架冠桃,最近開設(shè)了微信群中有兄弟說異常處理這塊可以優(yōu)化優(yōu)化并給出了建議參考項(xiàng)目歇盼,果斷重新將之前的封裝完善走起來舶赔,將請求過程中的處理統(tǒng)一封裝起來湃交,回調(diào)給調(diào)用者熟空,根據(jù)自定義回調(diào)類型方便查詢錯誤類型和信息。

前提

本章的內(nèi)容基于掌握了前面封裝的原理以后搞莺,學(xué)期起來才能完全的理解
RxJava+Retrofit+OkHttp深入淺出-終極封裝專欄

效果:

20161213112322273.gif

通過統(tǒng)一的異常處理息罗,可以實(shí)現(xiàn)各種異常的統(tǒng)一處理,然后通過統(tǒng)一回調(diào)給使用者才沧,方便統(tǒng)一展示和顯示提示給用戶

  • 第一條錯誤:故意修改了service里面方法地址迈喉,導(dǎo)致錯誤

  • 第二條錯誤:過期token,服務(wù)器返回的錯誤信息


優(yōu)化之路

1.定義回調(diào)異常類

定義的回調(diào)類温圆,方便回調(diào)接口統(tǒng)一處理挨摸,其中包含錯誤code和錯誤信息displayMessage

public class ApiException extends Exception{
    /*錯誤碼*/
    private int code;
    /*顯示的信息*/
    private String displayMessage;

    public ApiException(Throwable e) {
        super(e);
    }

    public ApiException(Throwable cause,@CodeException.CodeEp int code, String showMsg) {
        super(showMsg, cause);
        setCode(code);
        setDisplayMessage(showMsg);
    }

    @CodeException.CodeEp
    public int getCode() {
        return code;
    }

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

    public String getDisplayMessage() {
        return displayMessage;
    }

    public void setDisplayMessage(String displayMessage) {
        this.displayMessage = displayMessage;
    }
}

2.定義錯誤碼

自定義錯誤碼,相關(guān)的錯誤碼可以自行設(shè)定規(guī)則岁歉,框架現(xiàn)在給出了常用的錯誤碼定義得运,采用上一章講解的Android注解方式來定義錯誤碼的使用:

public class CodeException {

    /*網(wǎng)絡(luò)錯誤*/
    public static final int NETWORD_ERROR = 0x1;
    /*http_錯誤*/
    public static final int HTTP_ERROR = 0x2;
    /*fastjson錯誤*/
    public static final int JSON_ERROR = 0x3;
    /*未知錯誤*/
    public static final int UNKNOWN_ERROR = 0x4;
    /*運(yùn)行時(shí)異常-包含自定義異常*/
    public static final int RUNTIME_ERROR = 0x5;
    /*無法解析該域名*/
    public static final int UNKOWNHOST_ERROR = 0x6;


    @IntDef({NETWORD_ERROR, HTTP_ERROR, RUNTIME_ERROR, UNKNOWN_ERROR, JSON_ERROR, UNKOWNHOST_ERROR})
    @Retention(RetentionPolicy.SOURCE)

    public @interface CodeEp {
    }

}

因?yàn)槭窃?a href="http://www.reibang.com/p/bf949ee41c29" target="_blank">Rxjava+ReTrofit+okHttp深入淺出-終極封裝六特殊篇(變種String替換Gson自由擴(kuò)展)基礎(chǔ)上完善的異常處理,這里解析使用的是 fastjson的異常定義json解析異常

3.完善自定義運(yùn)行時(shí)異常

HttpTimeException類在之前的封裝中就已經(jīng)存在锅移,通過它在處理服務(wù)器返回錯誤信息和緩存錯誤信息熔掺,所以我們只是完善它的調(diào)用規(guī)則,讓它更加合理

public class HttpTimeException extends RuntimeException {
    /*未知錯誤*/
    public static final int UNKOWN_ERROR = 0x1002;
    /*本地?zé)o緩存錯誤*/
    public static final int NO_CHACHE_ERROR = 0x1003;
    /*緩存過時(shí)錯誤*/
    public static final int CHACHE_TIMEOUT_ERROR = 0x1004;


    public HttpTimeException(int resultCode) {
        this(getApiExceptionMessage(resultCode));
    }

    public HttpTimeException(String detailMessage) {
        super(detailMessage);
    }

    /**
     * 轉(zhuǎn)換錯誤數(shù)據(jù)
     *
     * @param code
     * @return
     */
    private static String getApiExceptionMessage(int code) {
        switch (code) {
            case UNKOWN_ERROR:
                return "錯誤:網(wǎng)絡(luò)錯誤";
            case NO_CHACHE_ERROR:
                return "錯誤:無緩存數(shù)據(jù)";
            case CHACHE_TIMEOUT_ERROR:
                return "錯誤:緩存數(shù)據(jù)過期";
            default:
                return "錯誤:未知錯誤";
        }
    }
}

完善后:加入code碼和對應(yīng)的錯誤信息

4.建立異常工廠類

異常工廠類中非剃,通過傳入對應(yīng)的Throwable錯誤置逻,然后根據(jù)Throwable的不同類型,生成不同的與之對應(yīng)的ApiException異常备绽,最后將ApiException異常返回給最后的rx回調(diào)onerror方法诽偷,最后onerror方法統(tǒng)一對異常進(jìn)行處理(如果你的需求又這樣的要求)回調(diào)給用戶界面;

public class FactoryException {
    private static final String HttpException_MSG = "網(wǎng)絡(luò)錯誤";
    private static final String ConnectException_MSG = "連接失敗";
    private static final String JSONException_MSG = "fastjeson解析失敗";
    private static final String UnknownHostException_MSG = "無法解析該域名";

    /**
     * 解析異常
     *
     * @param e
     * @return
     */
    public static ApiException analysisExcetpion(Throwable e) {
        ApiException apiException = new ApiException(e);
        if (e instanceof HttpException) {
             /*網(wǎng)絡(luò)異常*/
            apiException.setCode(CodeException.HTTP_ERROR);
            apiException.setDisplayMessage(HttpException_MSG);
        } else if (e instanceof HttpTimeException) {
             /*自定義運(yùn)行時(shí)異常*/
            HttpTimeException exception = (HttpTimeException) e;
            apiException.setCode(CodeException.RUNTIME_ERROR);
            apiException.setDisplayMessage(exception.getMessage());
        } else if (e instanceof ConnectException||e instanceof SocketTimeoutException) {
             /*鏈接異常*/
            apiException.setCode(CodeException.HTTP_ERROR);
            apiException.setDisplayMessage(ConnectException_MSG);
        } else if (e instanceof JSONPathException || e instanceof JSONException || e instanceof ParseException) {
             /*fastjson解析異常*/
            apiException.setCode(CodeException.JSON_ERROR);
            apiException.setDisplayMessage(JSONException_MSG);
        }else if (e instanceof UnknownHostException){
            /*無法解析該域名異常*/
            apiException.setCode(CodeException.UNKOWNHOST_ERROR);
            apiException.setDisplayMessage(UnknownHostException_MSG);
        } else {
            /*未知異常*/
            apiException.setCode(CodeException.UNKNOWN_ERROR);
            apiException.setDisplayMessage(e.getMessage());
        }
        return apiException;
    }
}

這個異常工廠類中的異常判斷在實(shí)際開發(fā)中疯坤,可以動態(tài)的自己添加报慕,可以將分類更加細(xì)化完善!

5.rx錯誤異常的轉(zhuǎn)換

rx在鏈接調(diào)用過程中產(chǎn)生的異常默認(rèn)是通過Subscriber的onError(Throwable e)方法回調(diào)压怠,這里我們需要將Throwable 轉(zhuǎn)換成自定義ApiException回調(diào),所以需要調(diào)用rxjava中的onErrorResumeNext方法眠冈,在異常回調(diào)前通過異常工廠類FactoryException處理返回統(tǒng)一的ApiException菌瘫。

偽代碼

****
******
********
 Observable observable = basePar.getObservable(httpService)
                /*失敗后的retry配置*/
                .retryWhen(new RetryWhenNetworkException())
                /*異常處理*/
                .onErrorResumeNext(funcException)

**********

  /**
     * 異常處理
     */
    Func1 funcException = new Func1<Throwable, Observable>() {
        @Override
        public Observable call(Throwable throwable) {
            return Observable.error(FactoryException.analysisExcetpion(throwable));
        }
    };         

6.回調(diào)結(jié)果的統(tǒng)一處理

  • 1.因?yàn)楦臑榻y(tǒng)一的錯誤毀掉類型蜗顽,需要修改之前的回到接口類
/**
 * 成功回調(diào)處理
 * Created by WZG on 2016/7/16.
 */
public interface  HttpOnNextListener {
    /**
     * 成功后回調(diào)方法
     * @param resulte
     * @param mothead
     */
   void onNext(String resulte,String mothead);

    /**
     * 失敗
     * 失敗或者錯誤方法
     * 自定義異常處理
     * @param e
     */
    void onError(ApiException e);
}
  • 2.onError(Throwable e)回調(diào)處理
 /**
     * 錯誤統(tǒng)一處理
     *
     * @param e
     */
    private void errorDo(Throwable e) {
        Context context = mActivity.get();
        if (context == null) return;
        HttpOnNextListener httpOnNextListener = mSubscriberOnNextListener.get();
        if (httpOnNextListener == null) return;
        if (e instanceof ApiException) {
            httpOnNextListener.onError((ApiException) e);
        } else if (e instanceof HttpTimeException) {
            HttpTimeException exception=(HttpTimeException)e;
            httpOnNextListener.onError(new ApiException(exception,CodeException.RUNTIME_ERROR,exception.getMessage()));
        } else {
            httpOnNextListener.onError(new ApiException(e, CodeException.UNKNOWN_ERROR,e.getMessage()));
        }
        /*可以在這里統(tǒng)一處理錯誤處理-可自由擴(kuò)展*/
        Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
    }

這里可以統(tǒng)一對異常進(jìn)行統(tǒng)一處理,默認(rèn)現(xiàn)在是toast提示雨让,當(dāng)然也有回調(diào)的傳遞

  • 3.顯示界面
    @Override
    public void onNext(String resulte, String mothead) {
       *****
    }

    @Override
    public void onError(ApiException e) {
        tvMsg.setText("失敼透恰:\ncode=" + e.getCode()+"\nmsg:"+e.getDisplayMessage());
    }

最后統(tǒng)一回調(diào)在onError中傳遞回一個ApiException對象

源碼

傳送門-GitHub-戳我

終極封裝專欄

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市栖忠,隨后出現(xiàn)的幾起案子崔挖,更是在濱河造成了極大的恐慌贸街,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狸相,死亡現(xiàn)場離奇詭異薛匪,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)脓鹃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進(jìn)店門逸尖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人瘸右,你說我怎么就攤上這事娇跟。” “怎么了太颤?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵苞俘,是天一觀的道長。 經(jīng)常有香客問我栋齿,道長,這世上最難降的妖魔是什么襟诸? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任瓦堵,我火速辦了婚禮,結(jié)果婚禮上歌亲,老公的妹妹穿的比我還像新娘菇用。我一直安慰自己,他們只是感情好陷揪,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布惋鸥。 她就那樣靜靜地躺著,像睡著了一般悍缠。 火紅的嫁衣襯著肌膚如雪卦绣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天飞蚓,我揣著相機(jī)與錄音滤港,去河邊找鬼。 笑死趴拧,一個胖子當(dāng)著我的面吹牛溅漾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播著榴,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼添履,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了脑又?” 一聲冷哼從身側(cè)響起暮胧,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤锐借,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后叔壤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瞎饲,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年炼绘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嗅战。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡俺亮,死狀恐怖驮捍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情脚曾,我是刑警寧澤东且,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站本讥,受9級特大地震影響珊泳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拷沸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一色查、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧撞芍,春花似錦秧了、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至帝嗡,卻和暖如春晶通,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背哟玷。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工录择, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人碗降。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓隘竭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親讼渊。 傳聞我的和親對象是個殘疾皇子动看,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評論 2 351

推薦閱讀更多精彩內(nèi)容