RxJava2.0學習筆記

  • 核心:異步 觀察者模式
  • 作用:RxJava的特點就是可以非常簡便的實現異步調用,可以在邏輯復雜的代碼邏輯中以比較輕易的方式實現異步調用。隨著邏輯的復雜,需求的更改,代碼可依然能保持極強的閱讀性,在深入的使用過程中一定對這點深有體會。
  • 引入:
 compile 'io.reactivex.rxjava2:rxjava:2.0.1'
 compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
  • 關鍵字
    Observable:在觀察者模式中稱為“被觀察者”;
    Observer:觀察者模式中的“觀察者”,可接收Observable發送的數據;
    subscribe:訂閱,觀察者與被觀察者,通過subscribe()方法進行訂閱;
    Subscriber:也是一種觀察者,在2.0中 它與Observer沒什么實質的區別,不同的是 Subscriber要與Flowable(也是一種被觀察者)聯合使用,該部分內容是2.0新增的,Obsesrver用于訂閱Observable,而Subscriber用于訂閱Flowable.
    Flowable:是一個被觀察者,
    ObservableEmitter:Emitter是發射器的意思,那就很好猜了,這個就是用來發出事件的,它可以發出三種類型的事件,通過調用emitter的onNext(T value)、onComplete()和onError(Throwable error)就可以分別發出next事件、complete事件和error事件。
    Disposable:這個單詞的字面意思是一次性用品,用完即可丟棄的.調用dispose()并不會導致上游不再繼續發送事件, 上游會繼續發送剩余的事件.
    Scheduler:相當于線程控制器,RxJava 通過它來指定每一段代碼應該運行在什么樣的線程。RxJava 已經內置了幾個 Scheduler ,它們已經適合大多數的使用場景,實現發送消息和接受消息在不同線程中進行的目的。
  • RxJava中的觀察者模式
    觀察者模式的概念很好理解,具體可以解釋為:A 對象(觀察者)對 B 對象(被觀察者)的某種變化高度敏感,需要在 B 變化的一瞬間做出反應。
    在程序的觀察者模式,觀察者不需要時刻盯著被觀察者(例如 A 不需要每過 2ms 就檢查一次 B 的狀態),而是采用注冊(Register)或者稱為訂閱(Subscribe)的方式,告訴被觀察者:我需要你的某某狀態,你要在它變化的時候通知我。

RxJava的使用

  • Observable的創建:
Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                //執行一些其他操作
                //.............
                //執行完畢,觸發回調,通知觀察者
                e.onNext("發射數據");
            }
        });
  • Observer的創建:
Observer<String> observer = new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            //觀察者接收到通知
            public void onNext(String aLong) {
                System.out.println("收到數據");
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {

            }
        };
  • 建立連接
observable.subscribe(observer);
  • Observable的創建除了常用的create方法外還有just()方式,fromIterable()方式,defer()方式,interval( )方式,range( )方式,timer( )方式,repeat( )方式,參考這篇文章http://www.lxweimin.com/p/d149043d103a

  • Scheduler線程控制器的使用:正常邏輯下我們在那個線程中發送消息就會在那個線程中接受消息,而我們在開發中更多想要的是這么一種情況, 在子線程中做耗時的操作, 然后回到主線程中來操作UI,要達到這個目的, 我們需要先改變上游發送事件的線程, 讓它去子線程中發送事件, 然后再改變下游的線程, 讓它去主線程接收事件. 通過RxJava內置的線程調度器可以很輕松的做到這一點. 接下來看一段代碼:

@Override                                                                                       
protected void onCreate(Bundle savedInstanceState) {                                            
    super.onCreate(savedInstanceState);                                                         
    setContentView(R.layout.activity_main);                                                     

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

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

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

可以看到打印結果為

 D/TAG: Observable thread is : RxNewThreadScheduler-2  
 D/TAG: emit 1                                         
 D/TAG: Observer thread is :main                       
 D/TAG: onNext: 1

可以看到, 上游發送事件的線程的確改變了, 是在一個叫 RxNewThreadScheduler-2的線程中發送的事件, 而下游仍然在主線程中接收事件, 這說明我們的目的達成了, 接下來看看是如何做到的.
實現這一過程的是這兩行代碼:

observable.subscribeOn(Schedulers.newThread())                                              
            .observeOn(AndroidSchedulers.mainThread())                                          
            .subscribe(consumer); 
  • 簡單的來說, subscribeOn() 指定的是上游發送事件的線程, observeOn() 指定的是下游接收事件的線程.多次指定上游的線程只有第一次指定的有效, 也就是說多次調用subscribeOn()只有第一次的有效, 其余的會被忽略.多次指定下游的線程是可以的, 也就是說每調用一次observeOn() , 下游的線程就會切換一次.

RxJava中的操作符

MAP

map是RxJava中最簡單的一個變換操作符了, 它的作用就是對上游發送的每一個事件應用一個函數, 使得每一個事件都按照指定的函數去變化.例如將發送的int數據統一變為String,代碼如下

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(TAG, s);
            }
        });

輸出結果為

 D/TAG: This is result 1 
 D/TAG: This is result 2 
 D/TAG: This is result 3

FlatMap

FlatMap將一個發送事件的上游Observable變換為多個發送事件的Observables,然后將它們發射的事件合并后放進一個單獨的Observable里.

ZIP用法

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

Observable<Integer> observable1 = Observable.create(new ObservableOnSubscribe<Integer>() {         
    @Override                                                                                      
    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {                   
        Log.d(TAG, "emit 1");                                                                      
        emitter.onNext(1);                                                                         
        Thread.sleep(1000);                                                                        

        Log.d(TAG, "emit 2");                                                                      
        emitter.onNext(2);                                                                         
        Thread.sleep(1000);                                                                        

        Log.d(TAG, "emit 3");                                                                      
        emitter.onNext(3);                                                                         
        Thread.sleep(1000);                                                                        

        Log.d(TAG, "emit 4");                                                                      
        emitter.onNext(4);                                                                         
        Thread.sleep(1000);                                                                        

        Log.d(TAG, "emit complete1");                                                              
        emitter.onComplete();                                                                      
    }                                                                                              
}).subscribeOn(Schedulers.io());                                                                   

Observable<String> observable2 = Observable.create(new ObservableOnSubscribe<String>() {           
    @Override                                                                                      
    public void subscribe(ObservableEmitter<String> emitter) throws Exception {                    
        Log.d(TAG, "emit A");                                                                      
        emitter.onNext("A");                                                                       
        Thread.sleep(1000);                                                                        

        Log.d(TAG, "emit B");                                                                      
        emitter.onNext("B");                                                                       
        Thread.sleep(1000);                                                                        

        Log.d(TAG, "emit C");                                                                      
        emitter.onNext("C");                                                                       
        Thread.sleep(1000);                                                                        

        Log.d(TAG, "emit complete2");                                                              
        emitter.onComplete();                                                                      
    }                                                                                              
}).subscribeOn(Schedulers.io());                                                                   

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");                                                                  
    }                                                                                              
});

運行結果為

D/TAG: onSubscribe    
D/TAG: emit A         
D/TAG: emit 1         
D/TAG: onNext: 1A     
D/TAG: emit B         
D/TAG: emit 2         
D/TAG: onNext: 2B     
D/TAG: emit C         
D/TAG: emit 3         
D/TAG: onNext: 3C     
D/TAG: emit complete2 
D/TAG: onComplete

ZIP應用場景

比如一個界面需要展示用戶的一些信息, 而這些信息分別要從兩個服務器接口中獲取, 而只有當兩個都獲取到了之后才能進行展示, 這個時候就可以用Zip了:

Observable<UserBaseInfoResponse> observable1 =                                            
        api.getUserBaseInfo(new UserBaseInfoRequest()).subscribeOn(Schedulers.io());      

Observable<UserExtraInfoResponse> observable2 =                                           
        api.getUserExtraInfo(new UserExtraInfoRequest()).subscribeOn(Schedulers.io());    

Observable.zip(observable1, observable2,                                                  
        new BiFunction<UserBaseInfoResponse, UserExtraInfoResponse, UserInfo>() {         
            @Override                                                                     
            public UserInfo apply(UserBaseInfoResponse baseInfo,                          
                                  UserExtraInfoResponse extraInfo) throws Exception {     
                return new UserInfo(baseInfo, extraInfo);                                 
            }                                                                             
        }).observeOn(AndroidSchedulers.mainThread())                                      
        .subscribe(new Consumer<UserInfo>() {                                             
            @Override                                                                     
            public void accept(UserInfo userInfo) throws Exception {                      
                //do something;                                                           
            }                                                                             
        });

Subscriber和Flowable的使用

  • ObservableObserver是一對被觀察者和觀察者,兩者通過subscribe連接在一起實現我們處理異步的過程。那么SubscriberFlowable又有什么用呢?這一對和上面介紹的那一對又有什么區別呢?
    • 為什么要使用SubscriberFlowableObservableObserver在處理同步訂閱也就是在一個線程中的時候上游發送一個事件下游接受一個事件是沒有什么問題的,而當處理異步訂閱也就是上游和下游不在同一個線程中時上游發送數據不需要等待下游接收, 因為兩個線程并不能直接進行通信, 因此上游發送的事件并不能直接到下游里去, 上游把所有的事件發送到一個可以存儲的池里面去(相當于Handler中的消息隊列), 下游從隊列里取出事件來處理, 因此, 當上游發事件的速度太快, 下游取事件的速度太慢, 隊列就會迅速裝滿, 然后溢出來, 最后就OOM了.當然我們也可以通過控制上游消息的發送速度和發送數量來控制。不過SubscriberFlowable的出現就完美的解決了OOM這個問題.
    • 使用SubscriberFlowable基本的用法:
Flowable<Integer> upstream = Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
                Log.d(TAG, "emit 1");
                emitter.onNext(1);
                Log.d(TAG, "emit 2");
                emitter.onNext(2);
                Log.d(TAG, "emit 3");
                emitter.onNext(3);
                Log.d(TAG, "emit complete");
                emitter.onComplete();
            }
        }, BackpressureStrategy.ERROR); //增加了一個參數

        Subscriber<Integer> downstream = new Subscriber<Integer>() {

            @Override
            public void onSubscribe(Subscription s) {
                Log.d(TAG, "onSubscribe");
                s.request(Long.MAX_VALUE);  //注意這句代碼
            }

            @Override
            public void onNext(Integer integer) {
                Log.d(TAG, "onNext: " + integer);

            }

            @Override
            public void onError(Throwable t) {
                 Log.w(TAG, "onError: ", t);
            }

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

        upstream.subscribe(downstream);
  • 首先是創建Flowable的時候增加了一個參數, 這個參數是用來選擇背壓,也就是出現上下游流速不均衡的時候應該怎么處理的辦法, 這里我們直接用BackpressureStrategy.ERROR這種方式, 這種方式會在出現上下游流速不均衡的時候直接拋出一個異常,這個異常就是著名的MissingBackpressureException. 其余的策略后面再來講解.
  • 另外的一個區別是在下游的onSubscribe方法中傳給我們的不再是Disposable了, 而是Subscription, 它倆有什么區別呢, 首先它們都是上下游中間的一個開關, 之前我們說調用Disposable.dispose()方法可以切斷水管, 同樣的調用Subscription.cancel()也可以切斷水管, 不同的地方在于Subscription增加了一個void request(long n)方法, 這個方法有什么用呢, 在上面的代碼中也有這么一句代碼:
s.request(Long.MAX_VALUE);
  • 因為Flowable在設計的時候采用了一種新的思路也就是響應式拉取的方式來更好的解決上下游流速不均衡的問題,我們把request當做是一種能力, 當成下游處理事件的能力, 下游能處理幾個就告訴上游我要幾個, 這樣只要上游根據下游的處理能力來決定發送多少事件, 就不會造成一窩蜂的發出一堆事件來, 從而導致OOM.

[RxJava 與 Retrofit 結合請求數據]
(http://gank.io/post/56e80c2c677659311bed9841)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容