RxJava2.x学习总结

RxJava2.x学习文档

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

  • RxJava2.x学习文档
    • 一、Observable 的创建
    • 二、Flowable 的创建
    • 三、常用的简化版的Observer
      • 3.1 Single
      • 3.2 Completable
      • 3.3 Maybe
    • 四、线程切换
      • 4.1 subScribeOn
      • 4.2 observeOn
      • 4.3 compose 代码复用
    • 五、操作符
      • 5.1 map 操作符
      • 5.2 flatMap 操作符
      • 5.3 concatMap 操作符
      • 5.4 zip 操作符
      • 5.5 interval 操作符
      • 5.6 repeat 操作符
      • 5.7 range 操作符
      • 5.8 fromArray操作符
      • 5.9 fromIterable操作符
      • 5.10 delay 操作符
    • 六、背压
      • 6.1 背压概念
      • 6.2 背压策略
    • 七、RxBinding的使用
      • 7.1 防抖处理
      • 7.2 长按事件
      • 7.3 listView 的点击事件、长按事件处理
      • 7.4 CheckBox 勾选事件
      • 7.5 搜索联想功能
    • 八、生命周期控制和内存优化
      • 8.1 取消订阅
      • 8.2 RxLifecycle 框架的使用
        • 8.2.1 bindToLifecycle 方法
        • 8.2.2 bindUntilEvent( ActivityEvent event)


用一句话描述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) 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(
        Consumersuper T> onNext, 
        Consumersuper Throwable> onError,
        Action onComplete, Consumersuper Disposable> onSubscribe) {
        ... ...
        //核心代码,实际上就是新构造了一个LambdaObserver定阅数据源;
        LambdaObserver ls = new LambdaObserver(onNext, onError, onComplete, onSubscribe);
        subscribe(ls);
        return ls;
    }

二、Flowable 的创建

1.创建Flowable被观察者对象,并给订阅者发射数据,获得数据后给界面展示.

 public Flowable 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 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 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 subscribeOn(Scheduler scheduler) {
        ObjectHelper.requireNonNull(scheduler, "scheduler is null");
        return RxJavaPlugins.onAssembly(new ObservableSubscribeOn(this, scheduler));
    }

4.2 observeOn

observeOn 方法用于指定下游 Observer 回调发生的线程。

@SchedulerSupport(SchedulerSupport.CUSTOM)
    public final Observable observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
        ObjectHelper.requireNonNull(scheduler, "scheduler is null");
        ObjectHelper.verifyPositive(bufferSize, "bufferSize");
        return RxJavaPlugins.onAssembly(new ObservableObserveOn(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 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 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 getStringObservable() {
        return Observable.create( e->{
            e.onNext("A");
            e.onNext("B");
            e.onNext("C");
        });
    }

    //创建 Integer 发射器
    private Observable 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 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 adapter = new ArrayAdapter(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 students = 
                         RealmService.getRealmService().queryStudentBy(charSequence);
                     return students;
                 })
             .subscribe(new Action1>() {
                 @Override
                 public void call(List 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.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.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 类似,都是枚举类,用法是一样的.

你可能感兴趣的:(Android,常用知识)