我學 rxjava 2(1)- 簡單上手

本系列目錄:我學 rxjava - 目錄
Android 知識梳理目錄:知識梳理

啥叫 rxjava

官方文檔解釋:

RxJava:a library for composing asynchronous and event-based programs using observable sequences for the Java VM
// 翻譯:RxJava 是一個在 Java VM 上使用可觀測的序列來組成異步的、基于事件的程序的庫

通俗解釋:

//  Android中的 AsyncTask 、Handler

rxjava 完成的工作就是異步,期中采用了響應式編程的理念,現在響應式編程不明白沒關系,不影響你用 rxjava 完成開發,響應式編程現在桃李滿天下呢,用不了多久就明白了并深有體會了,推薦學完 rxjava 再去看 Google 的 AAC 響應式組件,你就對響應式編程非常明白了,這里不要臉的推薦自己的文章:Android Architecture Components 開發架構

添加依賴

dependencies {

// Android 支持 Rxjava
// 此處一定要注意使用RxJava2的版本
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'

// Android 支持 Retrofit
compile 'com.squareup.retrofit2:retrofit:2.1.0'

// 銜接 Retrofit & RxJava
// 此處一定要注意使用RxJava2的版本
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'

// 支持Gson解析
compile 'com.squareup.retrofit2:converter-gson:2.1.0'

}

依賴可能的錯誤如下:


944365-b3574a3808108707.png

請在相關 module 中的 build.gradle 中

android {
    ...
    packagingOptions {
        exclude 'META-INF/rxjava.properties'
    }
}

rxjava 采用的是觀察者設計模式, 必然就是在 Observable 被觀察者 身上注冊 Observer 觀察者了,我們定義 Observable 如何產生,產生什么數據,然后 Observer 如何消費數據,整個套路基本就是這樣,當然里面有很設置和變化啦

rxjava 里面有很多沒接觸過的,不好記的關鍵字,記住這些關鍵字才能玩的轉 rxjava

關鍵字:

  • 被觀察者(Observable) 產生事件 顧客
  • 觀察者(Observer) 接收事件,并給出響應動作 廚房
  • 訂閱(Subscribe) 連接 被觀察者 & 觀察者 服務員
  • 事件(Event) 被觀察者 & 觀察者 溝通的載體 菜式

創建 Observable 被觀察者對象

rxjava 中的 Observable 被觀察者一般都是要傳入數據,或是能產生數據的對象才能創建出來的,所以我也喜歡管 Observable 叫數據源,要是沒有 Observable 這個數據源提供數據,后面怎么消費數據呢

  // 傳入可以產生數據的對象方式創建 Observable  對象
  Observable<String> object = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                // emitter 是用來提供數據的,我們也叫發射 
                emitter.onNext("數據");
            }
        });
    
        // 直接用數據創建 Observable  對象,數據可以是單個也可以是動態數組,集合
        Observable<String> just = Observable.just("aaa");
        Observable<String> list = Observable.just("", "", "");

創建 Observer 觀察者并定義處理事件的行為

 Observer<String> observer = new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                // 觀察者在接受到數據之前,先執行該方法
            }

            @Override
            public void onNext(String value) {
                // 觀察者此時接受到數據,可以處理數據了
            }

            @Override
            public void onError(Throwable e) {
                // 觀察者接受到錯誤信號,進行相關處理
            }

            @Override
            public void onComplete() {
                //  觀察者此時已經處理完數據了,執行該方法最最后的收尾工作。
            }
        };

Observer 觀察者里面有4個方法,上面的方法里的文字基本描述清楚了,然后我想說下 Error 錯誤信號可以用前面 數據源里面的 emitter.onError(xxx) 自己發射出來,也會接受到這個過程中系統拋出的異常。onComplete 是不管什么情況最后都會走的。

現在 Observable 有了 ,Observer 也有了,他倆一注冊就成了。

observable.subscribe(observer);

我們要注意數據產生的點,Observable 只是提供數據,不是我們創建一個 Observable 對象就去獲取數據,發射數據了,而是再 Observer 注冊到 Observable 身上那一瞬間,Observable 才還是提供數據,是遠程數據的開始從遠程獲取數據,是現成數據的開始發射數據給 Observer 消費數據。

線程變換

觀察者設計模式只是對 數據源 和 數據消費者 的一種組織形式,還不是 rxjava 最核心的內容,大家可以不要忘了 rxjava 可是替代 asynctask ,handle 這樣的異步線程啊,方便的多線程操作和切換才是 rxjava 最大的核心內容

rxjava 提供一下幾個線程池:

  • Schedulers.immediate()
    當前線程
  • AndroidSchedulers.mainThread()
    Android主線程
  • Schedulers.newThread()
    常規新線程
  • Schedulers.io()
    io操作線程,可以進行網絡請求、讀寫文件等io密集型操作
  • Schedulers.computation()
    CPU計算操作線程,線程數據同 CPU 核心數

相關的線程控制 API 如下,這里是簡單的寫的

 observable
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);
  • subscribeOn 是描述 observable 中產生數據的方法執行在哪個線程
  • observeOn 是描述 observer 消費數據的方法執行在哪個線程
  • 這里 數據源是從網絡獲取數據,UI 線程消費數據

關于 Observer 的變形

我們按照上面的 方式創建一個 Observer 來,需要實現4個方法才行,豐富多看著亂,頁影響 rxjava 的鏈式調用閱讀效果,官方提供了如下的 Observer 創建方法

   // 表示觀察者不對被觀察者發送的事件作出任何響應(但被觀察者還是可以繼續發送事件)
    public final Disposable subscribe()
 
    // 表示觀察者只對被觀察者發送的Next事件作出響應
    public final Disposable subscribe(Consumer<? super T> onNext) {}
  
    // 表示觀察者只對被觀察者發送的Next事件 & Error事件作出響應
    public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {} 
    
    // 表示觀察者只對被觀察者發送的Next事件、Error事件 & Complete事件作出響應
    public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete) {}
    
    // 表示觀察者只對被觀察者發送的Next事件、Error事件 、Complete事件 & onSubscribe事件作出響應
    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) {}

Consumer 是一個方法包裝接口,Observer 中的4個方法對應 4個 Consumer 方法包裝接口,subscribe 注冊方法中可以接受 1 - 4個 Consumer 可變參數,根據下面圖 4個方法的順序,傳入一個是代替 onNext 方法,傳入2個是代替 onNext、onError 方法

Consumer_方法包裝接口_替換方法順序如下

關于可能的內存泄露的處理

這些注冊的 Observer 我們都是在 activity 中進行的,按照:匿名內部類持有外不累的引用,這個注冊的匿名 Observer 對象其實是把我們的 activity 帶出 activity 的生命周期外去了,Observable 持有這些注冊的 Observer 對象引用,那么間接的也持有了 activity 的引用,在 activity 關閉時這就是個麻煩事了,原因不就是老生常談的內存泄露了嘛...

針對這個情況,其實我們是游處理辦法的,那就是 Disposable 管道這個對象,Disposable 是實際管理 Observable和 Observer 關系的操作類,我們用 Disposable 就可以接觸 Observable 和 Observer 的注冊的關系。

Disposable 有2種獲取方式,一個是注冊時我們使用 Consumer 代替 Observer ,然后我們就可以獲取這個 Disposable 對象,調用 disposable.dispose() 就可以解綁

        Disposable disposable = Observable
                .just("22")
                .subscribe(
                        new Consumer<String>() {
                            @Override
                            public void accept(String s) throws Exception {

                            }
                        }
                        , new Consumer<Throwable>() {
                            @Override
                            public void accept(Throwable throwable) throws Exception {

                            }
                        });

        disposable.dispose();

或者是 Observer 對象中的 onSubscribe(Disposable d) 方法中,我們可以獲取到 Disposable 對象

若是我們有多個 disposable 對象,我們可以使用官方提供管理類

        CompositeDisposable compositeDisposable = new CompositeDisposable();
        // 添加 disposable 管道對象用于統一管理
        compositeDisposable.add( disposable );
        // 統一解綁
        compositeDisposable.dispose();

一個完成的流程示例

rxjava 2 中添加了不少 doOnXXX 方法,打都是在指定的 OnXXX 方法之前執行的。

需要注意的是 2個 observeOn 方法中間夾一個 doOnNext 方法,這是說前一個 observeOn 指定 這個 doOnNext 方法的執行線程,后一個 observeOn 方法執行最終執行 Observer 執行線程,其實這個就是 rxjava 的變換操作符的基礎

  Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
                Log.d(TAG, " subscribe.../thread: " + Thread.currentThread().getName() + "處理數據,產生事件");
                e.onNext("HH");
            }
        })
                .subscribeOn(Schedulers.io())
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(Disposable disposable) throws Exception {
                        Log.d(TAG, " doOnSubscribe.../thread: " + Thread.currentThread().getName() + "預熱方法(doOnSubscribe函數),最先執行");
                    }
                })
                .observeOn(Schedulers.computation())
                .doOnNext(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {
                        Log.d(TAG, " doOnNext.../thread: " + Thread.currentThread().getName() + "數據處理后,先執行我,再發射數據");
                    }
                })
                .observeOn(Schedulers.newThread())
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        Log.d(TAG, " onSubscribe.../thread: " + Thread.currentThread().getName() + "預熱方法(觀察者),最先執行");
                    }

                    @Override
                    public void onNext(@NonNull String s) {
                        Log.d(TAG, " onNext.../thread: " + Thread.currentThread().getName() + "接受數據,消費事件");
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });

一個完整的簡單實用就是這樣了,這里各種生命周期函數寫的比較全了,直接看結果:


Snip20171010_25.png

按照執行順序:

  • doOnSubscribe() 方法最先執行,所在線程是UI 線程,調用測試方法的線程
  • subscribe / onSubscribe() ,之后是觀察者新添加方法,所在線程也是UI 線程,和doOnSubscribe()一樣,這倆用一個就行
  • create / subscribe() ,接下來是處理數據,發射事件的線程
  • doOnNext(),這個是在數據發射之前執行的,我們可以指定一個線程,這里指定的計算線程,要是不注定,則使用發射事件的線程
  • Observer / onNext(),最后就是我們接受事件啦。

注意上面各種方法所在線程,不要弄混了

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

推薦閱讀更多精彩內容