優美的異步 --- RxAndroid

轉載:https://www.jianshu.com/p/7eb5ccf5ab1e

 

優美的異步 --- RxAndroid

這裏和大家一起分享一下一個著名的Android異步庫RxAndroid。它應該是2016年最流行的開源庫之一。RxAndroid起源於RxJava,是一個專門針對Android版本的Rxjava庫。RxAndroid-Github 目前最新的版本是v2.0.x我們今天的分享也基於2.0版本的API。

響應式編程

什麼是響應式編程?和平常經常聽說的面向對象編程和函數式編程一樣,響應式編程(Reactive Programming)就是一個編程範式,但是與其他編程範式不同的是它是基於數據流和變化傳播的。我們經常在程序中這樣寫

A = B + C

A被賦值爲B和C的值。這時,如果我們改變B的值,A的值並不會隨之改變。而如果我們運用一種機制,當B或者C的值發現變化的時候,A的值也隨之改變,這樣就實現了響應式
而響應式編程的提出,其目的就是簡化類似的操作,因此它在用戶界面編程領域以及基於實時系統的動畫方面都有廣泛的應用。另一方面,在處理嵌套回調的異步事件,複雜的列表過濾和變換的時候也都有良好的表現。
RxAndroid其實是一個響應式編程思想的實現庫。也因爲這樣的思想,是它在一些方面表現的異常優秀。下面我將先用一個簡單的例子,讓大家直觀的感受一下的樣子。

網絡加載圖片顯示

Observable.just(getDrawableFromNet())
        .subscribeOn(Schedulers.newThread())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Consumer<Drawable>() {
            @Override
            public void accept(Drawable drawable) throws Exception {
                ((ImageView)findViewById(R.id.imageView)).setImageDrawable(drawable);
            }
        });

環境搭建

RxAndroid環境只需求要引入如下項目即可,我們不但需要RxAndroid項目還需要RxJava項目。

compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile 'io.reactivex.rxjava2:rxjava:2.1.5'

基礎知識

RxAndroid的核心就是“異步”兩個字,其最關鍵的東西就是三個:

Observable(被觀察者)
Observer(觀察者)
Subscriber (訂閱)
Observable可以理解爲事件的發送者,就好像快遞的寄出者,而這些事件就好比快遞
Observer可以理解爲事件的接收者,就好像快遞的接收者

Subscriber 綁定兩者

Observable可以發出一系列的 事件,這裏的事件可以是任何東西,例如網絡請求、複雜計算處理、數據庫操作、文件操作等等,事件執行結束後交給 Observer回調處理。

那他們之間是如何進行聯繫的呢?答案就是通過subscribe()方法。
下面我們通過一個HelloDemo來看看Observable與Observer進行關聯的典型方式,

  private void test_1() {
        Observable<String> oble = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
                e.onNext("hello");
                e.onComplete();
                e.onNext("hello2");

            }
        });

        Observer<String> oser = new Observer<String>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                Log.w("kaelpu","onSubscribe");
            }

            @Override
            public void onNext(@NonNull String s) {
                Log.w("kaelpu","onNext = "+s);
            }

            @Override
            public void onError(@NonNull Throwable e) {
                Log.w("kaelpu","onError" + e);
            }

            @Override
            public void onComplete() {
                Log.w("kaelpu","onComplete");
            }
        };

        Log.w("kaelpu","subscribe");
        oble.subscribe(oser);

    }

10-21 01:28:01.600 11386-11386/? W/kaelpu: subscribe
10-21 01:28:01.600 11386-11386/? W/kaelpu: onSubscribe
10-21 01:28:01.600 11386-11386/? W/kaelpu: onNext = hello
10-21 01:28:01.600 11386-11386/? W/kaelpu: onComplete

其實這段代碼幹了三件事:

  1. 創建被觀察者對象oble
  2. 創建觀察者oser
  3. 連接觀察者和被觀察者

被觀察者通過onNext函數給觀察者通知結果
被貫徹者onComplete函數通知觀察者執行結束
連接觀察者和被觀察者我們使用subscribe函數

  • 通過打印的log我們可以看到觀察者函數調用情況,調用subscribe函數去綁定觀察者和被觀察者時候,觀察者的onSubscribe函數會被回調錶示建立關聯。
  • 接着每當被觀察者調用onNext給觀察者發送數據時候,觀察者的onNext 會收到回調,並且得到所發送的數據。
  • 當被觀察者調用onComplete函數時候,代表着完成,觀察者的onComplete回調會被觸發,並且斷開了兩者的關聯,這時被觀察者再發送數據,觀察者也不會收到。

當然我們注意到觀察者還有一個onError函數沒有被觸發過,那麼該怎麼觸發呢,又代表着什麼意思呢?我們來改變一下代碼:

    private String error() throws Exception {
        throw new Exception();
    }

添加一個函數,名字隨便但是返回值是String,這裏我們叫做error函數。函數很簡單就是拋出一個異常。然後我們繼續修改被觀察者的代碼如下:

  Observable<String> oble = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
                e.onNext("hello");
                e.onNext(error());
                e.onNext("hello1");
                e.onComplete();
                e.onNext("hello2");

            }
        });

其實我們就添加了兩行,添加了一個e.onNext(error()) 並且在之後還添加了一個e.onNext("hello1") 運行一下我們看看

W/kaelpu: subscribe
W/kaelpu: onSubscribe
W/kaelpu: onNexthello
W/kaelpu: onErrorjava.lang.Exception

折斷log說明三個問題:

  1. 被觀察者onNext中是可以運行函數的
  2. 如果運行的函數報錯,則會調用我們觀察者的onError函數
  3. 當調用onError函數時候,也會斷開關聯,被觀察者收不到後面的數據,但是觀察者依然會繼續發送。

最爲關鍵的是onComplete和onError必須唯一併且互斥, 即不能發多個onComplete, 也不能發多個onError, 也不能先發一個onComplete, 然後再發一個onError, 反之亦然。

關於onComplete和onError唯一併且互斥這一點, 是需要自行在代碼中進行控制, 如果你的代碼邏輯中違背了這個規則, 並不一定會導致程序崩潰. 比如發送多個onComplete是可以正常運行的, 依然是收到第一個onComplete就不再接收了, 但若是發送多個onError, 則收到第二個onError事件會導致程序會崩潰.當我們寫多個onComplete時,不會報錯。

除了被觀察者能斷開關聯,觀察者也能主動斷開連接,調用onSubscribe函數中傳入的對象Disposable的dispose()函數即可完成斷開連接,同樣關聯斷開後,被觀察者依然會繼續發送數據

**講到這裏第一感覺是不是?**

Paste_Image.png

就輸出個數字就這麼麻煩,完全沒看出哪裏方便了!彆着急我剛開始看RxAndroid文章也是這樣的感覺,而且很多網上的文章都沒有解釋這個問題。所以看一會你就更暈了。彆着急我一起深呼吸,來看看如何簡化操作

你可能覺得,我就打印幾個數,還要把Observable寫的那麼麻煩,能不能簡便一點呢?答案是肯定的,RxAndroid內置了很多簡化創建Observable對象的函數,比如Observable.just就是用來創建只發出一個事件就結束的Observable對象,上面創建Observable對象的代碼可以簡化爲一行

        Observable<String> observable = Observable.just("hello");

同樣對於Observer,這個例子中,我們其實並不關心OnComplete和OnError,我們只需要在onNext的時候做一些處理,這時候就可以使用Consumer類。

        Observable<String> observable = Observable.just("hello");
        Consumer<String> consumer = new Consumer<String>() {
           @Override
           public void accept(String s) throws Exception {
               System.out.println(s);
           }
        };
        observable.subscribe(consumer);

其實在RxAndroid中,我們可以爲 Observer中的三種狀態根據自身需要分別創建一個回調動作,通過Action 來替代onComplete():,通過Consumer來替代 onError(Throwable t)和onNext(T t)

Observable<String> observable = Observable.just("hello");
    Action onCompleteAction = new Action() {
        @Override
        public void run() throws Exception {
            Log.i("kaelpu", "complete");
        }
    };
    Consumer<String> onNextConsumer = new Consumer<String>() {
        @Override
        public void accept(String s) throws Exception {
            Log.i("kaelpu", s);
        }
    };
    Consumer<Throwable> onErrorConsumer = new Consumer<Throwable>() {
        @Override
        public void accept(Throwable throwable) throws Exception {
            Log.i("kaelpu", "error");
        }
    };
    observable.subscribe(onNextConsumer, onErrorConsumer, onCompleteAction);

}

subscribe()有多個重載的方法:

 public final Disposable subscribe() {}
 public final Disposable subscribe(Consumer<? super T> onNext) {}
 public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {} 
 public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete) {}
 public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete, Consumer<? super Disposable> onSubscribe) {}
 public final void subscribe(Observer<? super T> observer) {}

不帶任何參數的subscribe() 表示Observer不關心任何事件,Observable發送什麼數據都隨你
帶有一個Consumer參數的方法表示Observer只關心onNext事件, 其他的事件我假裝沒看見, 因此我們如果只需要onNext事件可以這麼寫

只要我們再本節中能明白觀察者和被觀察者之間是如何工作關聯的就可以


線程調度

關鍵的章節來了,看完上面的基礎知識,很多人都會感覺就一個發送,一個接收,不就是個觀察者模式嘛,感覺一點卵用都沒有,還寫這麼多回調方法!完全沒有看出什麼優點。那麼這一節就讓你看到RxAndroid真正厲害的地方。

正常情況下, Observer和Observable是工作在同一個線程中的, 也就是說Observable在哪個線程發事件, Observer就在哪個線程接收事件.
RxAndroid中, 當我們在主線程中去創建一個Observable來發送事件, 則這個Observable默認就在主線程發送事件.
當我們在主線程去創建一個Observer來接收事件, 則這個Observer默認就在主線程中接收事件,但其實在現實工作中我們更多的是需要進行線程切換的,最常見的例子就是在子線程中請求網絡數據,在主線程中進行展示

要達到這個目的, 我們需要先改變Observable發送事件的線程, 讓它去子線程中發送事件, 然後再改變Observer的線程, 讓它去主線程接收事件. 通過RxAndroid內置的線程調度器可以很輕鬆的做到這一點. 接下來看一段代碼:

Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
            Log.d("kaelpu", "Observable thread is : " + Thread.currentThread().getName());
            Log.d("kaelpu", "emitter 1");
            emitter.onNext(1);
        }
    });

    Consumer<Integer> consumer = new Consumer<Integer>() {
        @Override
        public void accept(Integer integer) throws Exception {
            Log.d("kaelpu", "Observer thread is :" + Thread.currentThread().getName());
            Log.d("kaelpu", "onNext: " + integer);
        }
    };

    observable.subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(consumer);
}

Observable thread is : RxNewThreadScheduler-1
emitter 1
Observer thread is :main
onNext: 1

可以看到, observable發送事件的線程的確改變了, 是在一個叫 RxNewThreadScheduler-1的線程中發送的事件, 而consumer 仍然在主線程中接收事件, 這說明我們的目的達成了, 接下來看看是如何做到的.

這段代碼只不過是增加了兩行代碼:

.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())

簡單的來說, subscribeOn() 指定的是Observable發送事件的線程, observeOn() 指定的是Observer接收事件的線程.
多次指定Observable的線程只有第一次指定的有效, 也就是說多次調用subscribeOn() 只有第一次的有效, 其餘的會被忽略.
多次指定Observer的線程是可以的, 也就是說每調用一次observeOn() , Observer的線程就會切換一次.例如:

observable.subscribeOn(Schedulers.newThread())
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .observeOn(Schedulers.io())
        .subscribe(consumer);

Observable thread is : RxNewThreadScheduler-1
emitter 1
Observer thread is :RxCachedThreadScheduler-2
onNext: 1

可以看到, Observable雖然指定了兩次線程, 但只有第一次指定的有效, 依然是在RxNewThreadScheduler線程中, 而Observer則跑到了RxCachedThreadScheduler 中, 這個CacheThread其實就是IO線程池中的一個.
在 RxAndroid 中,提供了一個名爲 Scheduler 的線程調度器,RxAndroid 內部提供了4個調度器,分別是:

  • Schedulers.io(): I/O 操作(讀寫文件、數據庫、網絡請求等),與newThread()差不多,區別在於io() 的內部實現是是用一個無數量上限的線程池,可以重用空閒的線程,因此多數情況下 io() 效率比 newThread() 更高。值得注意的是,在 io() 下,不要進行大量的計算,以免產生不必要的線程;
  • Schedulers.newThread(): 開啓新線程操作;
  • Schedulers.immediate(): 默認指定的線程,也就是當前線程;
  • Schedulers.computation():計算所使用的調度器。這個計算指的是 CPU 密集型計算,即不會被 I/O等操作限制性能的操作,例如圖形的計算。這個 Scheduler 使用的固定的線程池,大小爲 CPU 核數。值得注意的是,不要把 I/O 操作放在 computation() 中,否則 I/O 操作的等待時間會浪費 CPU;
  • AndroidSchedulers.mainThread(): Rxndroid 擴展的 Android 主線程;

這些內置的Scheduler已經足夠滿足我們開發的需求, 因此我們應該使用內置的這些選項, 在RxAndroid內部使用的是線程池來維護這些線程, 所有效率也比較高。

對於線程還需要注意

  • create() , just() , from() 等 --- 事件產生
  • map() , flapMap() , scan() , filter() 等 -- 事件加工
  • subscribe() -- 事件消費

事件產生:默認運行在當前線程,可以由 subscribeOn() 自定義線程
事件加工:默認跟事件產生的線程保持一致, 可由 observeOn() 自定義線程
事件消費:默認運行在當前線程,可以有observeOn() 自定義

好了說了這麼多了,我們來寫個簡單的異步的例子,看看實際效果。我們這個例子就以加載網絡圖片並顯示爲例:
首先我們寫一個耗時函數,用來模擬圖片請求

    // 模擬網絡請求圖片
    private Drawable getDrawableFromUrl(String url){
        try {
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return getResources().getDrawable(R.drawable.baidu);
    }

代碼很簡答,就是線程sleep 6秒,然後返回一張圖片,如果運行在主線程那就會NAR,然後我麼來用RxAndroid寫一下這個異步拉去圖片並顯是的操作!

Observable.just(getDrawableFromNet("http://www.baidu.com/icon.png"))
        .subscribeOn(Schedulers.newThread())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Consumer<Drawable>() {
            @Override
            public void accept(Drawable drawable) throws Exception {
                ((ImageView)findViewById(R.id.imageView)).setImageDrawable(drawable);
            }
        });

就這幾行代碼就搞定了!自己結合上面講的理解一下~這裏就不做解釋了!因爲我們還有更重要的一個環節,這個環節堪稱RxAndroid的精髓!

操作符的使用

在瞭解基本知識和線程調度後,我們來學習一下RxAndroid各種神奇的操作符

Map
Map是RxAndroid中最簡單的一個變換操作符了, 它的作用就是對Observable發送的每一個事件應用一個函數, 使得每一個事件都按照指定的函數去變化。

Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
            emitter.onNext(1);
            emitter.onNext(2);
            emitter.onNext(3);
        }
    }).map(new Function<Integer, String>() {
        @Override
        public String apply(Integer integer) throws Exception {
            return "This is result " + integer;
        }
    }).subscribe(new Consumer<String>() {
        @Override
        public void accept(String s) throws Exception {
            Log.d("kaelpu", s);
        }
    });

This is result 1
This is result 2
This is result 3

通過Map, 可以將Observable發來的事件轉換爲任意的類型, 可以是一個Object, 也可以是一個集合,功能非常強大

例子:還是以圖片加載的例子,我們傳進來一個圖片的路徑,然後通過Map把drawble轉換成bitmap再發送給觀察者

Observable.just(getDrawableFromNet())
        .map(new Function<Drawable, Bitmap>() {
            @Override
            public Bitmap apply(@NonNull Drawable drawable) throws Exception {
                BitmapDrawable bt = (BitmapDrawable)drawable;
                return bt.getBitmap();
            }
        })
        .subscribeOn(AndroidSchedulers.mainThread())
        .observeOn(Schedulers.newThread())
        .subscribe(new Consumer<Bitmap>() {
            @Override
            public void accept(Bitmap bitmap) throws Exception {

            }
        });

Observable –> map變換 –> Observable
url -> drawable -> bitmap

不用到處調代碼,直接一個鏈式操作... 是不是感覺很爽!

ZIP
Zip通過一個函數將多個Observable發送的事件結合到一起,然後發送這些組合到一起的事件. 它按照嚴格的順序應用這個函數。它只發射與發射數據項最少的那個Observable一樣多的數據。

Observable<Integer> observable1 = Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
            Log.d(TAG, "emitter 1");
            emitter.onNext(1);
            Log.d(TAG, "emitter 2");
            emitter.onNext(2);
            Log.d(TAG, "emitter 3");
            emitter.onNext(3);
            Log.d(TAG, "emitter 4");
            emitter.onNext(4);
            Log.d(TAG, "emit complete1");
            emitter.onComplete();
        }
    });

    Observable<String> observable2 = Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(ObservableEmitter<String> emitter) throws Exception {
            Log.d(TAG, "emitter A");
            emitter.onNext("A");
            Log.d(TAG, "emitter B");
            emitter.onNext("B");
            Log.d(TAG, "emitter C");
            emitter.onNext("C");
            Log.d(TAG, "emitter complete2");
            emitter.onComplete();
        }
    });

    Observable.zip(observable1, observable2, new BiFunction<Integer, String, String>() {
        @Override
        public String apply(Integer integer, String s) throws Exception {
            return integer + s;
        }
    }).subscribe(new Observer<String>() {
        @Override
        public void onSubscribe(Disposable d) {
            Log.d(TAG, "onSubscribe");
        }

        @Override
        public void onNext(String value) {
            Log.d(TAG, "onNext: " + value);
        }

        @Override
        public void onError(Throwable e) {
            Log.d(TAG, "onError");
        }

        @Override
        public void onComplete() {
            Log.d(TAG, "onComplete");
        }
    });

我們分別創建了observable, 一個發送1,2,3,4,Complete, 另一個發送A,B,C,Complete, 接着用Zip把發出的事件組合, 來看看運行結果吧:

onSubscribe
emitter 1
emitter 2
emitter 3
emitter 4
emit complete1
emitter A
onNext: 1A
emitter B
onNext: 2B
emitter C
onNext: 3C
emitter complete2
onComplete

觀察發現observable1發送事件後,observable2才發送
這是因爲我們兩個observable都是運行在同一個線程裏, 同一個線程裏執行代碼肯定有先後順序呀.

from
在Rxndroid的from操作符到2.0已經被拆分成了3個,fromArray, fromIterable, fromFuture接收一個集合作爲輸入,然後每次輸出一個元素給subscriber。

Observable.fromArray(new Integer[]{1, 2, 3, 4, 5}).subscribe(new Consumer<Integer>() {
    @Override
    public void accept(Integer integer) throws Exception {
        Log.i(TAG, "number:" + integer);
    }
});

number:1
number:2
number:3
number:4
number:5

注意:如果from()裏面執行了耗時操作,即使使用了subscribeOn(Schedulers.io()),仍然是在主線程執行,可能會造成界面卡頓甚至崩潰,所以耗時操作還是使用Observable.create(…);

filter
條件過濾,去除不符合某些條件的事件。舉個栗子:

Observable.fromArray(new Integer[]{1, 2, 3, 4, 5})
       .filter(new Predicate<Integer>() {
           @Override
           public boolean test(Integer integer) throws Exception {
               // 偶數返回true,則表示剔除奇數,留下偶數
               return integer % 2 == 0;

           }
       }).subscribe(new Consumer<Integer>() {
    @Override
    public void accept(Integer integer) throws Exception {
        Log.i(TAG, "number:" + integer);
    }
});

number:2
number:4

take
最多保留的事件數。

 Observable.just("1", "2", "6", "3", "4", "5").take(2).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onNext(String value) {
                Log.d(TAG,value);
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {

            }
        });

1
2

可以發現我們發送了6個String,最後只打印了前兩個,這就是take過濾掉的結果

doOnNext
如果你想在處理下一個事件之前做某些事,就可以調用該方法

Observable.fromArray(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}).filter(new Predicate<Integer>() {
    @Override
    public boolean test(Integer integer) throws Exception {
        // 偶數返回true,則表示剔除奇數
        return integer % 2 == 0;
    }
})// 最多保留三個,也就是最後剩三個偶數
        .take(3).doOnNext(new Consumer<Integer>() {
    @Override
    public void accept(Integer integer) throws Exception {
        // 在輸出偶數之前輸出它的hashCode
        Log.i(TAG, "hahcode = " + integer.hashCode() + "");
    }
}).subscribe(new Observer<Integer>() {
    @Override
    public void onSubscribe(Disposable d) {

    }

    @Override
    public void onNext(Integer value) {
        Log.i(TAG, "number = " + value);
    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onComplete() {

    }
});

hahcode = 2
number = 2
hahcode = 4
number = 4
hahcode = 6
number = 6


針對Android的一些擴展

RxAndroid是RxJava的一個針對Android平臺的擴展。它包含了一些能夠簡化Android開發的工具。
首先,AndroidSchedulers提供了針對Android的線程系統的調度器。需要在UI線程中運行某些代碼?很簡單,只需要使用AndroidSchedulers.mainThread():

retrofitService.getImage(url)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(bitmap -> myImageView.setImageBitmap(bitmap));

接着要介紹的就是AndroidObservable,它提供了跟多的功能來配合Android的生命週期。bindActivity()和bindFragment()方法默認使用AndroidSchedulers.mainThread()來執行觀察者代碼,這兩個方法會在Activity或者Fragment結束的時候通知被觀察者停止發出新的消息。

AndroidObservable.bindActivity(this, retrofitService.getImage(url))
    .subscribeOn(Schedulers.io())
    .subscribe(bitmap -> myImageView.setImageBitmap(bitmap);

我自己也很喜歡AndroidObservable.fromBroadcast()方法,它允許你創建一個類似BroadcastReceiver的Observable對象。下面的例子展示瞭如何在網絡變化的時候被通知到:

IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
AndroidObservable.fromBroadcast(context, filter)
    .subscribe(intent -> handleConnectivityChange(intent));

最後要介紹的是ViewObservable,使用它可以給View添加了一些綁定。如果你想在每次點擊view的時候都收到一個事件,可以使用ViewObservable.clicks(),或者你想監聽TextView的內容變化,可以使用ViewObservable.text()

ViewObservable.clicks(mCardNameEditText, false)
    .subscribe(view -> handleClick(view));

RxAndroid的一些使用場景

這裏總結了一些很合適使用RxAndroid的場景,供大家打開腦洞~分享時候有時間給大家看看demo

  1. 界面需要等到多個接口併發取完數據,再更新
Observable<String> observable1 = Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(ObservableEmitter<String> e) throws Exception {
            e.onNext("haha");
        }
    }).subscribeOn(Schedulers.newThread());

    Observable<String> observable2 = Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(ObservableEmitter<String> e) throws Exception {
            e.onNext("hehe");
        }
    }).subscribeOn(Schedulers.newThread());


    Observable.merge(observable1, observable2)
            .subscribeOn(Schedulers.newThread())
            .subscribe(new Observer<String>() {
                @Override
                public void onSubscribe(Disposable d) {

                }

                @Override
                public void onNext(String value) {
                    Log.d(TAG,value);
                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onComplete() {

                }
            });
  1. 界面按鈕需要防止連續點擊的情況
RxView.clicks(button)
        .throttleFirst(1, TimeUnit.SECONDS)
        .subscribe(new Observer<Object>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Object o) {
                Log.i(TAG, "do clicked!");
            }
        });
  1. 響應式的界面 比如勾選了某個checkbox,自動更新對應的preference

SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
RxSharedPreferences rxPreferences = RxSharedPreferences.create(preferences);

Preference<String> username = rxPreferences.getString("username");
Preference<Boolean> showWhatsNew = rxPreferences.getBoolean("show-whats-new", true);

username.asObservable().subscribe(new Action1<String>() {
  @Override public void call(String username) {
    Log.d(TAG, "Username: " + username);  讀取到當前值
  }
}

RxCompoundButton.checks(showWhatsNewView)
    .subscribe(showWhatsNew.asAction());

                        


 

 

 

                                                                                                                     by .k

 

關注"編程v",每一天漲一點

STAY HUNGRY & STAY FOOLISH

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章