RxJava Android實(shí)際應(yīng)用

這里的網(wǎng)絡(luò)請求部分在我的另一篇文章Retrofit + OkHttp3 + RxJava2中进统,后面用到的Retrofits坡锡、Api都是來自該項(xiàng)目的一些Demo

這里記錄一些最近開發(fā)的想法和思路,一步一步是怎么實(shí)現(xiàn)一個(gè)簡單功能院溺,并去考慮拓展楣嘁,逐步完善的過程。下面的需求實(shí)際是我自己的不斷考慮和改變的一個(gè)過程覆获,用來展示RxJava的一些優(yōu)勢马澈。實(shí)際項(xiàng)目開發(fā)中這些應(yīng)該提前就考慮到,但是需求總是變化的弄息,這些優(yōu)勢也或多或少的會(huì)有價(jià)值痊班。希望看完這篇文章你會(huì)有收獲。

開始

請求一個(gè)網(wǎng)絡(luò)結(jié)果并展示在View

Retrofit + OkHttp3 + RxJava2中的例子

Retrofit配置中默認(rèn)網(wǎng)絡(luò)請求在IO線程

TextView showView;
...
Retrofits.get(Api.class)
  .getServerInfo()
  //指定訂閱者在UI線程響應(yīng)
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(result -> {
     showView.setText(result.toString());
  });

異常抓取

這里用到了onErrorReturn關(guān)鍵字摹量,其作用就是當(dāng)錯(cuò)誤發(fā)生的時(shí)候返回一個(gè)默認(rèn)值給訂閱者涤伐。

Return的數(shù)據(jù)必須為Observable的數(shù)據(jù)類型,在Retrofits返回?cái)?shù)據(jù)中為Observable<BaseResult<T>>缨称,這里需要返回一個(gè)BaseResult<T>凝果,攜帶錯(cuò)誤信息

需求:網(wǎng)絡(luò)無法連接code1001,連接超時(shí)code為1002睦尽,解析錯(cuò)誤code為1100

這里新建一個(gè)工具類Observables器净。

public class Observables {
    public static <T> Function<Throwable, BaseResult<T>> getErrorReturn() {
        return throwable -> {
            BaseResult<T> result = new BaseResult<>();
            if (throwable instanceof ConnectException ) {
                result.setCode(1001);
                result.setMessage("無法訪問服務(wù)器");
            } else if (throwable instanceof SocketTimeoutException) {
                result.setCode(1002);
                result.setMessage("連接超時(shí)");
            } else if (throwable instanceof JsonParseException) {
                result.setCode(1100);
                result.setMessage("解析失敗");
            }
            return result;
        };
    }
  .....
}

添加到業(yè)務(wù)處理

TextView showView;
...
Retrofits.get(Api.class)
  .getServerInfo()
  .onErrorReturn(Observables.getErrorReturn())
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(result -> {
     showView.setText(result.toString());
  });

這里當(dāng)產(chǎn)生這3個(gè)Exception后就能直接返回錯(cuò)誤碼,方便上層處理

綁定生命周期

在很多異步處理請求中当凡,我們都需要判斷當(dāng)數(shù)據(jù)請求返回后山害,是否我當(dāng)前的頁面被銷毀,如果不做判斷直接使用會(huì)出現(xiàn)崩潰或者內(nèi)存泄露沿量。

思路:

  • 對Acitivy或者Fragment在生命周期做一個(gè)Observable當(dāng)生命周期改變的時(shí)候就發(fā)射當(dāng)前的狀態(tài)
  • 篩選生命周期的數(shù)據(jù)只發(fā)射結(jié)束的那一個(gè)數(shù)據(jù)
  • 使用takeUntil關(guān)鍵字浪慌,當(dāng)takeUntil設(shè)置的Observable發(fā)射任何一個(gè)數(shù)據(jù)時(shí)候,就取消訂閱

核心代碼(已Fragment為例)

static final int INIT = 0;
static final int RELEASE = 1;
Observable<Integer> mLife = BehaviorSubject.create();
...
  
...
@Override
public void onDestroyView() {
  mLife.onNext(RELEASE);
  super.onDestroyView();
}

Retrofits.get(Api.class)
  .getServerInfo()
  .onErrorReturn(getErrorReturn())
  //綁定生命周期
  .takeUntil(mLife.filter(state -> state == RELEASE))
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(result -> {
     showView.setText(result.toString());
  });

我的另一個(gè)項(xiàng)目RxApp實(shí)現(xiàn)了該功能朴则,這里就直接使用权纤。


  Retrofits.get(Api.class)
  .getServerInfo()
  .onErrorReturn(getErrorReturn())
  //綁定生命周期
  .compose(RxApp.with(this).bindLife())
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(result -> {
     showView.setText(result.toString());
  });

綁定一個(gè)Dialog

需求

  • 在開始請求時(shí)顯示Dialog
  • Dialog不可取消
  • 網(wǎng)絡(luò)請求結(jié)束關(guān)閉

這里用到關(guān)鍵字doOnLifecycle(final Consumer<? super Disposable> onSubscribe, final Action onDispose),用于在訂閱和取消訂閱的時(shí)候進(jìn)行回調(diào)。

需要注意的是doOnLifecycle并沒有默認(rèn)的線程調(diào)度器汹想,需要指定調(diào)度器在UI主線程

添加到工具類

public class Observables {
  ...
    public static <T> ObservableTransformer<T, T> bindDialog(Context context) {
        //具體樣式就不詳述了
        final Dialog dialog = new ProgressDialog(context);
        dialog.setCancelable(false);
        return upstream -> upstream.doOnLifecycle(disposable -> dialog.show(), dialog::dismiss)
                //設(shè)置在UI主線程執(zhí)行
                .subscribeOn(AndroidSchedulers.mainThread());
    }
}

使用

Retrofits.get(Api.class)
  .getServerInfo()
  .onErrorReturn(getErrorReturn())
  //綁定Dialog
  .compose(Observables.bindDialog(getActivity()))
  .compose(RxApp.with(this).bindLife())
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(result -> {
     showView.setText(result.toString());
  });

Dialog可取消同時(shí)取消請求

同樣使用關(guān)鍵字takeUntil來處理該流程

public class Observables {
  ...
    public static <T> ObservableTransformer<T, T> bindCancelDialog(Context context) {
        final Dialog dialog = new ProgressDialog(context);
        dialog.setCancelable(true);
        dialog.setCanceledOnTouchOutside(false);
        //定義取消觸發(fā)的Observable
        BehaviorSubject<Boolean> dialogCancelSubject = BehaviorSubject.create();
        dialog.setOnCancelListener(dialog1 -> dialogCancelSubject.onNext(true));
        return upstream -> upstream.doOnLifecycle(disposable ->dialog.show(),dialog::dismiss)
                .subscribeOn(AndroidSchedulers.mainThread())
                .takeUntil(dialogCancelSubject);
    }
}

使用

Retrofits.get(Api.class)
  .getServerInfo()
  .onErrorReturn(getErrorReturn())
  //綁定Dialog
  .compose(Observables.bindDialog(getActivity()))
  .compose(RxApp.with(this).bindLife())
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(result -> {
     showView.setText(result.toString());
  });

Dialog 2秒后可取消

使用Observable.timer來實(shí)現(xiàn)

public class Observables {
  ...
    public static <T> ObservableTransformer<T, T> bindCancelDialog(Context context) {
        final Dialog dialog = new ProgressDialog(context);
        dialog.setCancelable(true);
        dialog.setCanceledOnTouchOutside(false);
        BehaviorSubject<Boolean> dialogCancelSubject = BehaviorSubject.create();
        dialog.setOnCancelListener(dialog1 -> dialogCancelSubject.onNext(true));
        return upstream -> upstream.doOnLifecycle(disposable -> {
                    dialog.show();
                    Observable.timer(2, TimeUnit.SECONDS)
                            .observeOn(AndroidSchedulers.mainThread())
                            .subscribe(time -> {
                                if(dialog.isShowing()){
                                    Toast.makeText(context,"點(diǎn)擊返回可取消",Toast.LENGTH_SHORT).show();
                                    dialog.setCancelable(true);
                                }
                            });
                },
                dialog::dismiss)
                .subscribeOn(AndroidSchedulers.mainThread())
                .takeUntil(dialogCancelSubject);
    }
}

總結(jié)

上面介紹了如何從一個(gè)簡單的網(wǎng)絡(luò)外邓,到添加一系列的業(yè)務(wù)處理。不難發(fā)現(xiàn)RxJava優(yōu)勢古掏,

  • 代碼流程看起來聚合很高坐榆,而且很易讀懂(前提是你了解Rxjava的關(guān)鍵字的作用)
  • 在業(yè)務(wù)中間添加流程很簡單,方便以后的維護(hù)
  • 解耦很方便冗茸,很多功能性的處理我們可以直接提出成工具類席镀,使用compose進(jìn)行批量處理

好了就分享這么多,希望對大家有幫助夏漱。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末豪诲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子挂绰,更是在濱河造成了極大的恐慌屎篱,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件葵蒂,死亡現(xiàn)場離奇詭異交播,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)践付,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門秦士,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人永高,你說我怎么就攤上這事隧土。” “怎么了命爬?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵曹傀,是天一觀的道長。 經(jīng)常有香客問我饲宛,道長皆愉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任艇抠,我火速辦了婚禮幕庐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘练链。我一直安慰自己翔脱,他們只是感情好奴拦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布媒鼓。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪绿鸣。 梳的紋絲不亂的頭發(fā)上疚沐,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音潮模,去河邊找鬼亮蛔。 笑死,一個(gè)胖子當(dāng)著我的面吹牛擎厢,可吹牛的內(nèi)容都是我干的究流。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼动遭,長吁一口氣:“原來是場噩夢啊……” “哼芬探!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起厘惦,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤偷仿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后宵蕉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體酝静,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年羡玛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了别智。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡稼稿,死狀恐怖亿遂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情渺杉,我是刑警寧澤蛇数,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站是越,受9級(jí)特大地震影響耳舅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜倚评,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一浦徊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧天梧,春花似錦盔性、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛹尝。三九已至,卻和暖如春悉尾,著一層夾襖步出監(jiān)牢的瞬間突那,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來泰國打工构眯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留愕难,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓惫霸,卻偏偏與公主長得像猫缭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子壹店,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

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