天天看點

RxJava最重要的概念是什麼?

RxJava最重要的概念是什麼?幾個操作符友善你把資料變來變去,友善你做線程排程,讓你不用去看callback hell?确實很友善,但如果隻看到這一層,未免過于膚淺。以我用RxJava這幾年膚淺的體驗來看,RxJava最大的作用是提供一個優秀的,現成的響應式/流式調用封裝,而你隻需付出些許學習成本就可以少做很多工作。一個RxJava的調用鍊從create開始到subscribe結束,可以大概把整個調用鍊分為上遊、中遊、下遊,上遊資料源,中遊資料變換,下遊資料接收&展示。除非你變更整條調用鍊的資料結構,變更其中一塊對外輸出的資料,否則你修改上中下遊任何一塊都不會影響到其它地方,整條調用鍊可以起于應用的網絡層,終于UI層,完美契合中大規模工程中的分層架構。舉個例子,我的應用中使用者的系統賬号和IM賬号是分開的,IM是第三方SDK,而且使用者并不是一定要登入IM才能使用應用,但是進入IM相關的子產品時,需要檢查使用者是否登入,如果登入,檢查IM是否登入,如果沒登入,檢查是否緩存IM賬号,通過接口擷取IM賬号并登入IM。這麼一段邏輯用RxJava怎麼做?//reloadAccount = true : 無論目前狀态如何都重新加載賬号資料并執行登入

public Observable<Object> checkAndLogin(boolean reloadAccount) {
    // 資料上遊,檢查賬号狀态決定下一步操作
    return Observable.create((emitter) -> {
        if (!reloadAccount && isIMLogin) {
            emitter.onNext(ACTION_ALREADY_LOGIN);
            return;
        }
        if (!reloadAccount && hasCacheData()) {
            emitter.onNext(ACTION_CACHE_LOGIN);
            return;
        }
        // 使用者沒有登入系統賬号,向下遊傳回異常
        if (!UserDataManager.isLogin()) {
            emitter.onError(new ApiExecption("請先登入"));
            return;
        }
        emitter.onNext(ACTION_RELOAD_LOGIN);
    })
    // 資料變換,是否需要請求賬号資料
    .flatMap((Function)(actionCode) -> {
        if(actionCode == ACTION_RELOAD_LOGIN) {
            return NetworkManager.getIMAccount();
        }
        //按下遊定義資料格式建構緩存資料發送
        JSONObject cacheData = new JSONObject();
        cacheData.put("isLogin", actionCode == ACTION_ALREADY_LOGIN);
        cacheData.put("userId", cachedUserId);
        cacheData.put("password", cachedUserPwd);
        return Observable.just(cacheData);
    })
    // 執行IM登入
    .flatMap((Function) (data) -> {
        if ( data.optBoolean("isLogin", false)) {
            return Observable.just(new Object());
        }
        String userId = data.getString("userId");
        String password = data.getString("password");
        if (TextUtils.isEmpty(userId) || TextUtils.isEmpty(password)) {
            return Observable.error(new ApiExecption("擷取IM賬号失敗"));
        }
        cacheAccountData(userId, password);
        // 傳回RxJava封裝過後的第三方IM登入方法
        return rxIMLogin();
    })
    // 出現登入異常時請求賬号資料重試
    .onErrorResumeNext((Function)(throwable) -> {
        // 如果沒有重試次數則直接将異常交給下遊
        if (retryTimes <= 0) {
            return Observable.error(throwable);
        }
        retryTimes--;
        return checkAndLogin(true);
    })
    // 登入成功重試次數重置
    .map((Function)(o) -> {
        retryTimes = 1;
        return o;
    })
    .subscribeOn(Schedulers.io())
    .observableOn(AndroidSchedulers.mainThread());
}
           

這麼一段“中遊”代碼,封裝了是否強制重新加載賬号、檢查IM是否登入、檢查系統賬号是否登入、請求IM賬号、緩存已擷取賬号、執行IM登入,出錯重連,異常處理。而下遊的subscribe訂閱,隻需關心“IM登入了沒?”,在初始化界面,如果登入了就去請求預加載資料,如果沒登入就pass,不管異常。在IM界面,如果登入了就去請求其它IM資料,沒登入直接彈Alert提示異常并退出界面。這個例子應該能比較好的說明“流式調用”是怎麼回事了吧。你用其它手段能實作這一套邏輯嗎?當然能,而且很簡單,不過是你用另外一種方式實作了“流式調用”而已,隻是可能沒有RxJava實作的代碼這麼緊密,修改友善罷了。分層架構就是這樣,面向協定程式設計。比如分頁加載,我不管你上遊中遊要做多少事,下遊UI層隻關心拿到List,是否有更多,觸發加載更多時調用;中遊隻關心把資料變換成下遊所需的資料,RxJava用這些資料操作符實作了中遊不用關心上遊資料,上遊用接口請求資料下來,還是Observable.just()一段假資料下來,對中遊、下遊沒有絲毫影響。這種調用形式在某些用戶端先用假資料看效果,後端接口以後給到的情景下,實作和替換成本極其低廉。說了這麼多總結一下,元件間調用可以看作一個應用的“神經系統”,而RxJava相當于一套優秀的,現成的“神經信号傳遞機制”,要用,就要替換整個應用“神經系統的信号傳遞機制”。如果你的應用現行的機制已經運作良好使用友善,且替換成本高昂,那麼完全沒有必要為了Rx而內建RxJava,或者說你在寫随時可能拿去其它環境使用的元件,那更不能随便內建SDK;但如果你應用現在的互相調用寫的亂七八糟,或者開始搭建新應用,為什麼放着現成的機制不拿過來用而要自己再寫一套蹩腳的callback呢?

RxJava2和Rxjava1的差別:https://www.jianshu.com/p/4ac34c1411ca

RxJava1到Rxjava2踩過的坑:https://www.jianshu.com/p/6d644ca1678f

繼續閱讀