RxJava2.x學習總結

RxJava2.x學習文檔

CSDN:https://blog.csdn.net/chenzhen200638/article/details/81569036


用一句話描述RxJava的本質:
- RxJava採用觀察者模式,實現了數據發射(emitter)和數據接收並消費(consumer)響應式開發模式,並能靈活切換任務線程。

觀察者模式 RxJava 以觀察者模式爲骨架,在 2.0 中依舊如此,不過此次更新中,出現了兩種觀察者模式:
- Observable ( 被觀察者 ) / Observer ( 觀察者 )
- Flowable (被觀察者)/ Subscriber (觀察者)

Alt text

RxJava 2.x 中,Observable 用於訂閱 Observer,不再支持背壓(1.x 中可以使用背壓策略),而 Flowable 用於訂閱 Subscriber , 是支持背壓(Backpressure)的。

一、Observable 的創建


1.創建Observable被觀察者對象,並給訂閱者發射數據,獲得數據後給界面展示.

 public Observable queryStudentWithObservable(int age){
        return Observable.create( (ObservableOnSubscribe<Student>) e -> {
            Realm realm = Realm.getDefaultInstance();
            Student student = null;
            try {
                realm.beginTransaction();
                student = realm.where(Student.class).equalTo("age", age).findFirst();
                realm.commitTransaction();
            } catch (Exception ex) {
                ex.printStackTrace();
            }finally {
                if(student != null){
                    e.onNext(student);
                }else{
                    e.onError(new Throwable("沒有查到數據!"));
                }
            }
        });
    }
  1. 訂閱消息,並顯示查詢到的學生數據.
  public void queryStudentWithObservable(){
        container.removeAllViews();
        RealmService.getRealmService().queryStudentBy(15).subscribe(
                student-> container.addView(buildTextView(student.toString())),
                throwable-> Toast.makeText(this,throwable.toString(),Toast.LENGTH_LONG).show())
                .dispose();
    }

來看看subscibe的源碼實現, subscribe的參數有兩個:Consumer onNext,Consumer onError;

    @CheckReturnValue
    @SchedulerSupport(SchedulerSupport.NONE)
    public final Disposable subscribe(
        Consumer<? super T> onNext, 
        Consumer<? super Throwable> onError,
        Action onComplete, Consumer<? super Disposable> onSubscribe) {
        ... ...
        //核心代碼,實際上就是新構造了一個LambdaObserver定閱數據源;
        LambdaObserver<T> ls = new LambdaObserver<T>(onNext, onError, onComplete, onSubscribe);
        subscribe(ls);
        return ls;
    }

二、Flowable 的創建

1.創建Flowable被觀察者對象,並給訂閱者發射數據,獲得數據後給界面展示.

 public Flowable<Student> queryStudentWithFlowable(int age){
        return Flowable.create( e -> {
            Realm realm = Realm.getDefaultInstance();
            Student student = null;
            try {
                realm.beginTransaction();
                student = realm.where(Student.class).equalTo("age", age).findFirst();
                realm.commitTransaction();
            } catch (Exception ex) {
                ex.printStackTrace();
            }finally {
                if(student != null){
                    e.onNext(student);
                }else{
                    e.onError(new Throwable("沒有查到數據!"));
                }
            }
        }, BackpressureStrategy.BUFFER);
    }
  1. 訂閱消息,並顯示查詢到的學生數據.
  public void queryStudentWithObservable(){
        RealmService.getRealmService().queryStudentWithFlowable(15).subscribe(
                student-> container.addView(buildTextView(student.toString())),
                throwable-> Toast.makeText(this,throwable.toString(),Toast.LENGTH_LONG).show())
                .dispose();
    }

三、常用的簡化版的Observer

  • 1).在Rxjava2中,ObservaleFlowable都是用來發射數據流的。
  • 2).我們在實際應用中,很多時候,需要發射的數據並不是數據流的形式,而只是一條單一的數據,或者一條完成通知、或者一條錯誤的通知。
  • 3).在這種場景下,我們再使用Observable或者Flowable就顯得有點大材小用。於是,爲了滿足這種單一數據或通知的使用場景,便出現了Observable的簡化版: SingleCompletableMaybe

3.1 Single

應用場景: 只發射一條單一的數據,或者一條異常通知,不能發射完成通知,其中數據與通知只能發射一個結果.

實例: 查詢數據庫,成功則更新UI,失敗則提示沒有查詢到數據.
- Single.fromCallable(emitter->{})
或者
- Single.create(emitter->{});


/**
 *創建一個Single的數據源,根據年紀參數查詢學生數據;
**/
public Single<Student> findStudentBy(int age) {
        return Single.fromCallable(() -> {
            Realm realm = Realm.getDefaultInstance();
            Student student = null;
            try {
                realm.beginTransaction();
                student = realm.where(Student.class).equalTo("age", age).findFirst();
                realm.commitTransaction();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            if(student == null){
                throw new Exception("沒有查到數據!");
            }
            return student;
        });
 }

/**
 *查詢年紀爲15歲的學生
**/
public void singleQuerySample() {
        container.removeAllViews();
        Single<Student> s15 = RealmService.getRealmService().findStudentBy(15);
        s15.subscribe(
                student -> container.addView(buildTextView(student.toString())),
                error -> Toast.makeText(
                            MainActivity.this, 
                            error.toString(), 
                            Toast.LENGTH_LONG).show());
    }

3.2 Completable

應用場景: 只發射一條完成通知,或者一條異常通知,不能發射數據,其中完成通知與異常通知只能發射一個

例子:添加學生數據,不關注成功失敗,只關注事件完成與否。

  • Completeble.fromAction(emitter->{})
    或者
  • Completeble.create(emitter->{})

 /**
 * 添加學生數據,創建一個Completeble對象;
 **/
 public Completable addStudent(Student student) {
        //注意,這裏是通過fromAction來生成一個Completeble,即只關注單一的動作是否完成.
        return Completable.fromAction(() -> {
            Realm realm = Realm.getDefaultInstance();
            try {
                realm.executeTransaction(r -> {
                    Student s = realm.createObject(Student.class, UUID.randomUUID().toString());
                    s.setName(student.getName());
                    s.setAddress(student.getAddress());
                    s.setAge(student.getAge());
                    realm.copyFromRealm(s);
                });
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                if (realm != null) {
                    realm.close();
                }
            }
        });
    }

或者,也可以通過Completeble.create()來創建Completeble.

 public Completable addStudent(Student student) {
        return Completable.create( e -> {
            Realm realm = Realm.getDefaultInstance();
            try {
                realm.executeTransaction(r -> {
                    Student s = realm.createObject(Student.class, UUID.randomUUID().toString());
                    s.setName(student.getName());
                    s.setAddress(student.getAddress());
                    s.setAge(student.getAge());
                    realm.copyFromRealm(s);
                });
                //結束業務流程,發送通知完成了;
                e.onComplete();
            } catch (Exception ex) {
                ex.printStackTrace();
                //發生異常,發送一個異常通知;
                e.onError(ex);
            } finally {
                if (realm != null) {
                    realm.close();
                }
            }
        });

    }

然後在Activity中,調用這個接口添加學生數據,完成添加動作之後,更新數據和ui.


 /**
  *Activity中: 構造學生數據
 **/
public void  buildStudentDatas() {
        Student a = new Student();
        a.setAge(14);
        a.setAddress("中國北京");
        a.setName("周浩");

        Student b = new Student();
        b.setAge(15);
        b.setAddress("深圳小牛在線");
        b.setName("陳真");

        Student c = new Student();
        c.setAge(16);
        c.setAddress("中國上海");
        c.setName("文忠湖");

        //每添加一個學生的數據後,查詢並更新ui.
        RealmService.getRealmService().addStudent(a).subscribe(this::queryStudent);
        RealmService.getRealmService().addStudent(b).subscribe(this::queryStudent);
        RealmService.getRealmService().addStudent(c).subscribe(this::queryStudent);
    }

     /**
      *查詢所有學生數據,並更新界面
     */
    public void queryStudent() {
        container.removeAllViews();
        RealmService.getRealmService().findAllStudent()
                .subscribe(students -> {
                    for (Student s : students) {
                        container.addView(buildTextView(s.toString()));
                    }
                });
    }

3.3 Maybe

應用場景: 可發射一條單一的數據,以及發射一條完成通知,或者一條異常通知(onComplte()onError() 只能發射其中一個消息,同時發送的話onComplete()無效),其中完成通知和異常通知只能發射一個,發射數據只能在發射完成通知或者異常通知之前,否則發射數據無效。

例子: 根據年紀來查詢學生數據,查到了發送數據,沒查到要麼發送完成消息,要麼發送異常信息;

 public Maybe queryStudentWithMaybe(int age){
        return Maybe.create( e -> {
            Realm realm = Realm.getDefaultInstance();
            Student student = null;
            try {
                realm.beginTransaction();
                student = realm.where(Student.class).equalTo("age", age).findFirst();
                realm.commitTransaction();
            } catch (Exception ex) {
                ex.printStackTrace();
            }finally {
                if(student != null){
                    //如果查詢到結果發送數據;
                    e.onSuccess(student);
                }else{
                    //如果沒有查詢到數據,發送異常消息;
                    e.onError(new Throwable("沒有查到數據!"));
                }
                //事件完成發送完成通知;
                //e.onComplete();
            }
        });
    }

Activity中接收數據,並在ui中展示結果

    public void queryStudentWithMaybe() {
        container.removeAllViews();
        RealmService.getRealmService().queryStudentWithMaybe(15).subscribe(
                student -> container.addView(buildTextView(student.toString())),
                error -> Toast.makeText(MainActivity.this, error.toString(), Toast.LENGTH_LONG).show())
                .dispose();
    }

四、線程切換

4.1 subScribeOn

subscribeOn 用於指定 subscribe() 上游所發生的線程,從源碼角度可以看出,內部線程調度是通過 ObservableSubscribeOn 來實現的。

@SchedulerSupport(SchedulerSupport.CUSTOM)
    public final Observable<T> subscribeOn(Scheduler scheduler) {
        ObjectHelper.requireNonNull(scheduler, "scheduler is null");
        return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
    }

4.2 observeOn

observeOn 方法用於指定下游 Observer 回調發生的線程。

@SchedulerSupport(SchedulerSupport.CUSTOM)
    public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
        ObjectHelper.requireNonNull(scheduler, "scheduler is null");
        ObjectHelper.verifyPositive(bufferSize, "bufferSize");
        return RxJavaPlugins.onAssembly(new ObservableObserveOn<T>(this, scheduler, delayError, bufferSize));
    }

4.3 compose 代碼複用

4.3.1、RxJava 內置的線程調度器的確可以讓我們的線程切換得心應手,但其中也有些需要注意的地方。

  • 簡單地說,subscribeOn() 指定的就是發射事件的線程,observerOn 指定的就是訂閱者接收事件的線程;
  • 多次指定發射事件的線程只有第一次指定的有效,也就是說多次調用 subscribeOn()只有第一次的有效,其餘的會被忽略;
  • 但多次指定訂閱者接收線程是可以的,也就是說每調用一次 observerOn(),下游的線程就會切換一次;

4.3.2、RxJava 中,已經內置了很多線程選項供我們選擇,例如有:
- Schedulers.io() 代表io操作的線程, 通常用於網絡,讀寫文件等io密集型的操作;
- Schedulers.computation() 代表CPU計算密集型的操作, 例如需要大量計算的操作;
- Schedulers.newThread() 代表一個常規的新線程;
- AndroidSchedulers.mainThread() 代表Android的主線程


4.3.3、使用compose包裝代碼,重複利用代碼:

相信小夥伴在使用RXJava與Retrofit請求網絡時,都有遇到過這樣的場景,在IO線程請求網絡解析數據,接着返回主線程setData、更新View試圖,那麼也肯定熟悉下面這幾句代碼:

.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);

如果網絡請求的次數比較少, 作爲一名不拘小節.
但是如果請求網絡的biz次數多起來了,又不想去破環RX的鏈式結構,那麼怎麼辦呢?
其實使用compose操作符每次僅書寫一行代碼就能完成工作線程的切換了!

final Observable.Transformer schedulersTransformer = new  Observable.Transformer() {
 @Override public Object call(Object observable) {
   return ((Observable)  observable)
       .subscribeOn(Schedulers.newThread())
       .observeOn(AndroidSchedulers.mainThread());
  }
};

僅僅通過.compose(schedulersTransformer)行代碼就完成了線程切換.

RetrofitClient.singletonDemoService("http://gank.io/api/random/data/")
.requestNet("福利","1")
.compose(schedulersTransformer)
.subscribe(subscriber);

五、操作符

5.1 map 操作符

MapRxJava中最簡單的一個變換操作符,它的作用是將上游發送過來的事件都去應用一個函數,讓每一個事件都按照該函數去變化,下游接收到事件時,就變成了變化過後的事件。
例子:把數字轉換成字符串
官方文檔:http://reactivex.io/documentation/operators/map.html

Observable.create(e -> {
                    e.onNext(1);
                    e.onNext(2);
                    e.onNext(3);}
        ).map( upstream-> "0x"+String.valueOf(upstream))
        .subscribe(result-> container.addView(buildTextView(result)));

輸出結果:
0x1
0x2
0x3

5.2 flatMap 操作符

FlatMap,這個操作符和剛纔的Map有什麼區別呢?
FlatMap可以將上游發送過來的數據,變換爲多個數據,然後合併爲一個事件發送到下游。
例子: 所數據源 1, 2, 3變換成多個數據發送;
官方文檔: http://reactivex.io/documentation/operators/flatmap.html

 container.removeAllViews();
        Observable.create(e -> {
                    e.onNext(1);
                    e.onNext(2);
                    e.onNext(3);}
        ).flatMap( upstream-> {
            List<String> source = new ArrayList<>();
            for(int i=0; i<3; i++){
                source.add("0x"+ upstream);
            }
            return Observable.fromIterable(source);
        })
        .subscribe(result-> container.addView(buildTextView(result)));

輸出結果: 無序輸出
0x1
0x1
0x1
0x2
0x2
0x3
0x3
0x2
0x3

5.3 concatMap 操作符

ConcatMapFlatMap一樣,只不過一個是有序,一個是無序而已,我們直接把上邊的代碼做一個更改.

container.removeAllViews();
        Observable.create(e -> {
                    e.onNext(1);
                    e.onNext(2);
                    e.onNext(3);}
        ).concatMap( upstream-> {
            List<String> source = new ArrayList<>();
            for(int i=0; i<3; i++){
                source.add("0x"+ upstream);
            }
            return Observable.fromIterable(source);
        })
        .subscribe(result-> container.addView(buildTextView(result)));

輸出結果: 有序輸出
0x1
0x1
0x1
0x2
0x2
0x3
0x3
0x3
0x3

5.4 zip 操作符

構建一個 String 發射器 和 Integer 發射器

    //創建 String 發射器
    private Observable<String> getStringObservable() {
        return Observable.create( e->{
            e.onNext("A");
            e.onNext("B");
            e.onNext("C");
        });
    }

    //創建 Integer 發射器
    private Observable<Integer> getIntegerObservable() {
        return Observable.create(e-> {
                e.onNext(1);
                e.onNext(2);
                e.onNext(3);
                e.onNext(4);
                e.onNext(5);
        });
    }

使用 zip 操作符,打包合併兩個事件

private void zip(){
        Observable.zip(
                getStringObservable(),
                getIntegerObservable(),
                (string,integer)->string+integer).subscribe(
                        result-> container.addView(buildTextView(result))
                );
    }

輸出結果: 多出來的 4,5 被拋棄了,沒有匹配的數據合併;
A1
A2
A3

5.5 interval 操作符

interval操作符是每隔一段時間就產生一個數字,這些數字從0開始,一次遞增1直至無窮大;


public void interval(){
    Flowable.interval(1, TimeUnit.SECONDS)
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(result-> container.addView(buildTextView(String.valueOf(result))));

    或者

    Observable.interval(1, TimeUnit.SECONDS)
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(result-> container.addView(buildTextView(String.valueOf(result))));
}

輸出結果:
0
1
2
3
...
n

利用interval實現倒計時的功能, 倒計時5秒鐘


 public void countDown(){

     Observable.interval(1, TimeUnit.SECONDS)
                .map(source-> 5-source)
                .observeOn(AndroidSchedulers.mainThread())
                .take(5)
                .subscribe(result-> container.addView(buildTextView(String.valueOf(result))));
}

輸出結果:
5
4
3
2
1

5.6 repeat 操作符

該操作符用來重複發送數據源
- repeat( ) 無限重複
- repeat( int time ) 設定重複的次數

private void repeat(){
    Observable.just(1,2)
         .repeat(2)
         .subscribe(result-> container.addView(buildTextView(String.valueOf(result))));
}

輸出結果:
1
2
1
2

5.7 range 操作符

range 發射特定整數序列的 Observable
- range( int start , int end ) start :開始的值 , end :結束的值

private void range(){
    Observable
         .range( 1 , 5 )
         .subscribe(result-> container.addView(buildTextView(String.valueOf(result))));
}   

輸出結果:
1
2
3
4
5   

5.8 fromArray操作符

由一個數組充當數據源發射到訂閱者

private void fromArray(){
    Integer[] items = {0, 1, 2, 3, 4, 5};
    Observable
         .fromArray(items)
         .subscribe(result-> container.addView(buildTextView(String.valueOf(result))));
}   

輸出結果:
1
2
3
4
5   

5.9 fromIterable操作符

由一個集合充當數據源發射到訂閱者


public void fromIterable(){
    List<String> list = new ArrayList<>();
    list.add("a");
    list.add("b");
    list.add("c");

    Observable
            .fromIterable(list)
            .subscribe(result-> container.addView(buildTextView(String.valueOf(result))));
}

輸出結果:
a
b
c

5.10 delay 操作符

延遲數據源的發射

Observable
    .just(1, 2, 3)
    .delay(3, TimeUnit.SECONDS)  //延遲3秒鐘,然後在發射數據
    .subscribe(result-> container.addView(buildTextView(String.valueOf(result))));

六、背壓

6.1 背壓概念

RxJava是一個觀察者模式的架構,當這個架構中被觀察者(Observable)和觀察者(Subscriber)處在不同的線程環境中時,由於者各自的工作量不一樣,導致它們產生事件和處理事件的速度不一樣,這就會出現兩種情況:

  • 被觀察者產生事件慢一些,觀察者處理事件很快。那麼觀察者就會等着被觀察者發送事件。
  • 被觀察者產生事件的速度很快,而觀察者處理很慢。那就出問題了,如果不作處理的話,事件會堆積起來,最終擠爆你的內存,導致程序崩潰。

需要強調兩點:

  • 背壓策略的一個前提是異步環境,也就是說,被觀察者和觀察者處在不同的線程環境中。
  • 背壓(Backpressure)並不是一個像flatMap一樣可以在程序中直接使用的操作符,他只是一種控制事件流速的策略。

RxJava2.X中,Observeable用於訂閱Observer,是不支持背壓的,而Flowable用於訂閱Subscriber,是支持背壓(Backpressure)的。


6.2 背壓策略

  • onBackpressureBuffer:默認情況下緩存所有的數據,不會丟棄數據,這個方法可以解決背壓問題,但是它有像 Observable 一樣的缺點,緩存數據太多,佔用太多內存。

  • onBackpressureBuffer(int capacity) :設置緩存隊列大小,但是如果緩衝數據超過了設置的值,就會報錯,發生崩潰。

Flowable的三種Backpressure策略:
- BackpressureStrategy.BUFFER
- BackpressureStrategy.DROP
- BackpressureStrategy.LATEST

onBackpressureBuffer()不丟棄數據的處理方式。把上游收到的全部緩存下來,等下游來請求再發給下游。相當於一個水庫。但上游太快,水庫(buffer)就會溢出。


    private void backPressure(){
        Flowable.interval( 1 , TimeUnit.MILLISECONDS)
                .onBackpressureBuffer( 100) //設置緩衝隊列大小爲 1000
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(result-> container.addView(buildTextView(String.valueOf(result))));
    }

    上面代碼運行一段時間後,會報錯:
    08-13 11:28:57.262 32675-32675/realm.com.xn.realmdatabase E/AndroidRuntime: 
    FATAL EXCEPTION: main Process: realm.com.xn.realmdatabase, 
    PID: 32675 io.reactivex.exceptions.OnErrorNotImplementedException: Buffer is full

通過日誌可以看出,緩衝區已經滿了.

注:onBackpressureLatest就是隻保留最新的事件

七、RxBinding的使用

git地址:https://github.com/JakeWharton/RxBinding

需要的庫清單, 在gradle中添加以下庫

    implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
    implementation 'com.jakewharton.rxbinding2:rxbinding-support-v4:2.1.1'
    implementation 'com.jakewharton.rxbinding2:rxbinding-appcompat-v7:2.1.1'
    implementation 'com.jakewharton.rxbinding2:rxbinding-design:2.1.1'
    implementation 'com.jakewharton.rxbinding2:rxbinding-recyclerview-v7:2.1.1'
    implementation 'com.jakewharton.rxbinding2:rxbinding-leanback-v17:2.1.1'

7.1 防抖處理

  • 兩秒鐘之內只取一個點擊事件,防抖操作
    RxView.clicks(this.findViewById(R.id.addStudent))
                .throttleFirst(2,TimeUnit.SECONDS)
                .subscribe(v-> addStudent());

7.2 長按事件

按鈕的長按時間監聽

    RxView.longClicks(this.findViewById(R.id.Merge))
                .throttleFirst(2,TimeUnit.SECONDS)
                .subscribe(v-> merge());

7.3 listView 的點擊事件、長按事件處理

ListView 單擊事件

 ListView listView = this.findViewById(R.id.list);
 RxAdapterView.itemClicks(listView).subscribe(index-> onItemClick(index));

ListView 長按事件

 ListView listView = this.findViewById(R.id.list);
 RxAdapterView.itemLongClicks(listView).subscribe(index-> onItemClick(index));

7.4 CheckBox 勾選事件

checkBox = (CheckBox) findViewById( R.id.checkbox );
RxCompoundButton.checkedChanges(checkBox)
    .subscribe( status-> {
            button.setEnabled(status);
            button.setBackgroundResource( status ? R.color.button_yes : R.color.button_no );
    }) ;

7.5 搜索聯想功能

搜索的時候,關鍵詞聯想功能 ,debounce()在一定的時間內沒有操作就會發送事件;
實現數據庫根據輸入學生姓名匹配搜索功能

editText = (EditText) findViewById( R.id.editText );
listView = (ListView) findViewById( R.id.listview );

final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1 );
listView.setAdapter(adapter);

 RxTextView.textChanges(editText)
             .debounce( 600 , TimeUnit.MILLISECONDS )
             .observeOn( Schedulers.io() )
             .map(charSequence->{
                     //根據輸入的內容,模糊查詢學生信息
                     List<Student> students = 
                         RealmService.getRealmService().queryStudentBy(charSequence);
                     return students;
                 })
             .subscribe(new Action1<List<String>>() {
                 @Override
                 public void call(List<Student> students) {
                     adapter.clear();
                     adapter.addAll(students);
                     adapter.notifyDataSetChanged();
                 }
             }) ;

八、生命週期控制和內存優化

RxJava使我們很方便的使用鏈式編程,代碼看起來既簡潔又優雅。但是RxJava使用起來也是有副作用的,使用越來越多的訂閱,內存開銷也會變得很大,稍不留神就會出現內存溢出的情況,這篇文章就是介紹Rxjava使用過程中應該注意的事項。

8.1 取消訂閱

    String rmName = rmNameTextView.getText().toString();
    RealmService.getRealmService()
        .deleteStudentBy(rmName)
        .subscribe(this::queryStudent)
        .dispose();//也可以在onDestroy中銷燬

    或者
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //取消訂閱
        if ( subscription != null ){
            subscription.unsubscribe();
        }
    }

8.2 RxLifecycle 框架的使用

  • github地址: https://github.com/trello/RxLifecycle
  • android studio 裏面添加引用
    compile ‘com.trello:rxlifecycle-components:0.6.1’

  • 讓你的activity繼承RxActivity,RxAppCompatActivity,RxFragmentActivity
    讓你的fragment繼承RxFragment,RxDialogFragment;下面的代碼就以RxAppCompatActivity舉例


8.2.1 bindToLifecycle 方法

在子類使用Observable中的compose操作符,調用完成Observable發佈的事件和當前的組件綁定,實現生命週期同步。從而實現當前組件生命週期結束時,自動取消對Observable訂閱。

public class MainActivity extends RxAppCompatActivity {
        TextView textView ;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.textView);

        //循環發送數字
        Observable.interval(0, 1, TimeUnit.SECONDS)
            .subscribeOn( Schedulers.io())
            //這個訂閱關係跟Activity綁定,Observable 和activity生命週期同步
            .compose(this.<Long>bindToLifecycle())   
            .observeOn( AndroidSchedulers.mainThread())
            .subscribe( time->textView.setText( String.valueOf( aLong ) ) );
       }
    }

上面的代碼是Observable循環的發送數字,並且在textview中顯示出來

  • 1.沒加 compose(this.bindToLifecycle()) 當Activiry 結束掉以後,Observable還是會不斷的發送數字,訂閱關係沒有解除
  • 2.添加compose(this.bindToLifecycle()) 當Activity結束掉以後,Observable停止發送數據,訂閱關係解除。

8.2.2 bindUntilEvent( ActivityEvent event)

從上面的例子可以看出bindToLifecycle() 方法可以使Observable發佈的事件和當前的Activity綁定,實現生命週期同步。也就是ActivityonDestroy() 方法被調用後,Observable 的訂閱關係才解除。那能不能指定在Activity其他的生命狀態和訂閱關係保持同步,答案是有的。就是bindUntilEvent()方法

  • ActivityEvent.CREATE: 在Activity的onCreate()方法執行後,解除綁定。

  • ActivityEvent.START:在Activity的onStart()方法執行後,解除綁定。

  • ActivityEvent.RESUME:在Activity的onResume()方法執行後,解除綁定。

  • ActivityEvent.PAUSE: 在Activity的onPause()方法執行後,解除綁定。

  • ActivityEvent.STOP:在Activity的onStop()方法執行後,解除綁定。

  • ActivityEvent.DESTROY:在Activity的onDestroy()方法執行後,解除綁定。

//循環發送數字
    Observable.interval(0, 1, TimeUnit.SECONDS)
        .subscribeOn( Schedulers.io())
        //當Activity執行Onstop()方法是解除訂閱關係
        .compose(this.<Long>bindUntilEvent(ActivityEvent.STOP ))   
        .observeOn( AndroidSchedulers.mainThread())
        .subscribe(time->textView.setText( String.valueOf( aLong ) ));

FragmentEvent 這個類是專門處理訂閱事件與Fragment生命週期同步

public enum FragmentEvent {
        ATTACH,
        CREATE,
        CREATE_VIEW,
        START,
        RESUME,
        PAUSE,
        STOP,
        DESTROY_VIEW,
        DESTROY,
        DETACH
}

可以看出FragmentEventActivityEvent 類似,都是枚舉類,用法是一樣的.

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