Rxjava总结

出处:http://gank.io/post/560e15be2dca930e00da1083#toc_26

一、什么是Rxjava?

    一个词:异步

    引入依赖:    compile 'io.reactivex:rxjava:1.0.14' 

                          compile 'io.reactivex:rxandroid:1.0.1' 

    API原理

1.概念:扩展的观察者模式。

    观察者模式面向的需求是:A对象(观察者)对B对象(被观察者)的某种变化有着高度的敏感,可以在B变化的一瞬间做出反应。而程序的观察者模式与这种观察有着略微的不同,观察者不需要时刻盯着被观察者,而是采取注册(Register)或者订阅(Subscribe)的方式,告诉被观察者:我需要你的某某状态,你要在它变化的时候通知我。android开发中一个比较典型的例子是点击监听器onClickListener,对设置onClickListener来说,view是被观察者,onClickListener是观察者,两者通过setonClickListener来达成订阅关系。

2.Rxjava的观察者模式

Rxjava有四个基本概念,Observable(可观察者,即被观察者),Observer(观察者),Subscribe(订阅),事件。

Observable和Observer是通过subscribe()的方法来实现订阅关系的,从而Observable可以在需要的时候发出事件来通知Observer。

Rxjava事件回调方法:

onCompleted():事件队列完结。Rxjava把每个事件单独处理,并且把每个事件看成一个队列。

onNext():普通事件方法。当不在有新的onNext()发出时,就会触发onCompleted()方法。

onError():事件队列异常。出现异常时调用,并且终止新事件的发出,队列自动终止。

在一个正常运行的事件序列中,onCompleted()方法和onError()方法有且只有一个会触发,并且是事件序列的最后一个。

2.基本实现

1.创建Observer(观察者), 它决定事件触发的时候将有怎样的行为

Observer observer = new Observer() {

     @Override 

     public void onNext(String s) {

      Log.d("zrl", "Observer_" +"onNext");

     }

     @Override 

     public void onCompleted() {

      Log.d("zrl", "Observer_" +"onCompleted");

     }

     @Override 

     public void onError(Throwable e) {

        Log.d("zrl", "Observer_" +"onError");

     }

};

除了Observer接口之外,Rxjava还内置了一个实现了Observer的抽象类:Subscriber。Subscriber对Observer进行了一些扩展,但基本方法的使用完全一样。

Subscriber subscriber =new Subscriber() {

    @Override

    public void onCompleted() {

        Log.d("zrl", "Subscriber_"+"onCompleted");

    }

    @Override

    public void onError(Throwable e) {

        Log.d("zrl", "Subscriber_"+"onCompleted");

    }

    @Override

    public void onNext(String s) {

        Log.d("zrl", "Subscriber_"+"onCompleted");

    }

    //subscriber刚开始,而事件还未发送时调用,可以用于做一些准备工作,例如数据的清零或重置

    @Override

    public void onStart() {

        super.onStart();

    }

};

不仅基本使用方式一样,实质上,在 RxJava 的 subscribe 过程中,Observer 也总是会先被转换成一个 Subscriber 再使用。所以如果你只想使用基本功能,选择 Observer 和 Subscriber 是完全一样的。而区别在于:

1)onStart():这是Subscriber新增的方法,他会在Subscrib刚开始,而事件还未发送之前调用,可以用于做一些准备工作,例如数据的清零或重置。

2)unSubscribe():这是Subscriber所实现的另一个接口Subscription的方法,用于取消订阅。在这个方法被调用后,Subscriber 将不再接收事件。一般在这个方法调用前,可以使用 isUnsubscribed() 先判断一下状态。 unsubscribe() 这个方法很重要,因为在 subscribe() 之后, Observable 会持有 Subscriber 的引用,这个引用如果不能及时被释放,将有内存泄露的风险。所以最好保持一个原则:要在不再使用的时候尽快在合适的地方(例如 onPause() onStop() 等方法中)调用 unsubscribe() 来解除引用关系,以避免内存泄露的发生。

2.创建Observable(被观察者), 它决定什么时候触发事件以及触发怎样的事件

Rxjava使用create()方法来创建一个Observable,并为它定义事件触发规则。

Observable observable = Observable.create(new Observable.OnSubscribe){

    @Override

    public void call(Subscriber subscriber){

        if(success){

            subscriber.onNext("zrl");

            subscriber.onNext(T);

        }

        else{

            subscriber.onError();

        }

        subscriber.onCompleted();

    }

}

可以看到,这里传入了一个OnSubscribe对象作为参数,OnSubscribe会被存储在返回的Observable对象中,当Observable被订阅的时候,call方法会自动被调用,然后事件会依次触发(按照上面的代码就是在成功条件下观察者会被调用两次onNext()方法,和一次onCompleted()方法)这样,是被观察者调用了观察者的方法,就实现了由被观察者向观察者传递事件,即观察者模式。

create() 方法是 RxJava 最基本的创造事件序列的方法。基于这个方法, RxJava 还提供了一些方法用来快捷创建事件队列,例如:

1)just(T...):将传入的参数依次发送出来。

Observable observable = Observable.just("Hello", "Hi", "Aloha");// 将会依次调用: onNext("Hello"); onNext("Hi"); onNext("Aloha"); onCompleted();

2)from(T[ ]) / from(Iterable):将传入的数组或者Iterable拆分成对象,然后依次发出来。

String[] words = {"Hello", "Hi", "Aloha"};

Observable observable = Observable.from(words);// 将会依次调用:onNext("Hello"); onNext("Hi"); onNext("Aloha"); onCompleted();

3.Subscribe(订阅)

创建了 Observable 和 Observer 之后,再用 subscribe() 方法将它们联结起来,整条链子就可以工作了

observable.subscribe(observer);

或者

observable.subscribe(subscriber);

内部实现是这样的(仅核心代码):

public Subscription subscribe(Subscriber subscriber) {

     subscriber.onStart(); 

     onSubscribe.call(subscriber);

     return subscriber;

}

可以看到,subscriber() 做了3件事:

调用 Subscriber.onStart() 。这个方法在前面已经介绍过,是一个可选的准备方法。

调用 Observable 中的 OnSubscribe.call(Subscriber) 。在这里,事件发送的逻辑开始运行。从这也可以看出,在 RxJava 中, Observable 并不是在创建的时候就立即开始发送事件,而是在它被订阅的时候,即当 subscribe() 方法执行的时候。

将传入的 Subscriber 作为 Subscription 返回。这是为了方便 unsubscribe().


除了subscribe(observer)和subscribe(subscriber)以外,subscribe()还支持不完整定义的回调,Rxjava会自动根据定义创建出subscriber。

ex:

Action1 onNextAction = new Action1(){

    //onNext

    @Override 

    public void call(String s) { Log.d("zrl", s); }

}

Action1 onErrorAction = new Action1(){

    //onError

     @Override 

    public void call(Throwable throwable) { // Error handling }

}

Action0 onCompletedAction = new Action0(){

     // onCompleted()

    @Override 

    public void call() { Log.d(tag, "completed"); }

}

// 自动创建 Subscriber ,并使用 onNextAction 来定义 onNext()

observable.subscribe(onNextAction);

// 自动创建 Subscriber ,并使用 onNextAction 和 onErrorAction 来定义 onNext() 和 onError()

observable.subscribe(onNextAction, onErrorAction);

// 自动创建 Subscriber ,并使用 onNextAction、 onErrorAction 和 onCompletedAction 来定义 onNext()、 onError() 和 onCompleted()

observable.subscribe(onNextAction, onErrorAction, onCompletedAction);


Action0是Rxjava的一个接口,它只有一个无参无返回值的call()方法,由于onCompleted()方法也是无参无返回值的,因此Action0可以被当成一个包装对象,将onCompleted()内容打包起来,将自己作为一个参数传入subscribe()以实现不完整意义的回调。

Action1 也是一个接口,它同样只有一个方法 call(T param),这个方法也无返回值,但有一个参数;与 Action0 同理,由于 onNext(T obj) 和 onError(Throwable error) 也是单参数无返回值的,因此 Action1 可以将 onNext(obj) 和 onError(error) 打包起来传入 subscribe() 以实现不完整定义的回调。

事实上,虽然 Action0 和 Action1 在 API 中使用最广泛,但 RxJava 是提供了多个 ActionX 形式的接口 (例如 Action2, Action3) 的,它们可以被用以包装不同的无返回值的方法。

ex1:

String[] arr = {"111", "2222", "444", "333", "555", "ddd", "sss", "aaa"};

Observable.from(arr).subscribe(new Action1() {

@Override

    public void call(String s) {

Log.d("zrl", s);

    }

});

ex2:

int imgId = R.drawable.msp_demo_title;

ImageView rx_img;

Observable.create(new Observable.OnSubscribe() {

@Override

    public void call(Subscriber subscriber) {

        Drawable drawable = ContextCompat.getDrawable(TriangleAct.this, imgId);

        subscriber.onNext(drawable);

        subscriber.onCompleted();

    }

}).subscribe(new Observer() {

    @Override

    public void onCompleted() {

    }

    @Override

    public void onError(Throwable e) {

    Toast.makeText(TriangleAct.this, "Error!", Toast.LENGTH_SHORT).show();

    }

    @Override

    public void onNext(Drawable drawable) {

    rx_img.setImageDrawable(drawable);

    }

});

如果只用上面的方法,实现出来的只是一个同步的观察者模式 ,要实现异步,则需要用到 RxJava 的另一个概念: Scheduler 。

4.线程控制--Scheduler(一)

在不指定线程的情况下, RxJava 遵循的是线程不变的原则,即:在哪个线程调用 subscribe(),就在哪个线程生产事件;在哪个线程生产事件,就在哪个线程消费事件。如果需要切换线程,就需要用到 Scheduler (调度器)。

Scheduler--调度器,相当于线程控制器,Rxjava用它来指定每一段代码要运行在什么样的线程,Rxjava已经内置了几个Scheduler:

1.Schedulers.immediate():直接在当前线程运行,相当于不指定线程。这是默认是Scheduler。

2.Schedulers.newThread():总是启用新线程,并在新线程执行操作。

3.Schedulers.io():I/O操作(读写文件,读写数据库,网络信息交互等)所用的Scheduler,行为模式与newThread()差不多,区别在于io()的内部实现是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下io()比newThread()更有效率。不要把计算工作放在io()中,可以避免创建不必要的线程。

4.Schedulers.computation():计算所使用的Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。

另外,Android还有一个专门用的AndroidSchedulers.mainThread()。它指定的操作将在android主线程中执行。

有了这几个Scheduler,就可以用subscribeOn()和observeOn()两个方法进行对线程的控制了,

subscribeOn():指定subscribe()所发生的的线程,即Observable.OnSubscribe被激活处所用的线程,或者叫做事件产生的线程

observeOn():指定Subscriber所运行的线程,或者叫做事件消费的线程。

Observable.just(1,2,3,4)

                   .subscribeOn(Schedulers.io())//指定subscribe()发生在io线程

                   .observeOn(AndroidSchedulers.mainThread())//指定Subscriber的回调发生在主线程

                   .subscribe(new Action1(){

                    @Override 

                    public void call(Integer number) { Log.d(tag, "number:" + number); } });

上面这段代码中,由于 subscribeOn(Schedulers.io()) 的指定,被创建的事件的内容 1、2、3、4 将会在 IO 线程发出;而由于 observeOn(AndroidScheculers.mainThread()) 的指定,因此 subscriber 数字的打印将发生在主线程 。事实上,这种在 subscribe() 之前写上两句 subscribeOn(Scheduler.io()) 和 observeOn(AndroidSchedulers.mainThread()) 的使用方式非常常见,它适用于多数的 『后台线程取数据,主线程显示』的程序策略

变换

Rxjava提供了对事件序列进行变换的支持,这是他的核心功能之一,所谓变换,就是将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列。

ex:

Observable.just("images/logo.png")//输出类型String

                    .map(new Func1(){

                        @Override 

                        public Bitmap call(String filePath) { // 参数类型 String 

                        return getBitmapFromPath(filePath); // 返回类型 Bitmap 

                 }

    })

        .subscribe(new Action1(){

              @Override 

              public void call(Bitmap bitmap) { // 参数类型 

                    Bitmap showBitmap(bitmap); }

});

这里出现了一个Func1类,他与Action1非常类似,也是Rxjava的一个接口,用于包装含有一个参数的方法。FuncX的方法是有返回值的,而ActionX方法没有返回值。

map()方法将参数中的String对象转换成了一个Bitmap对象后返回,而经历过map()后,事件的参数类型也由String变成了Bitmap。Rxjava不仅可以针对事件对象,还可以针对整个事件队列。

map():事件对象的直接变换,是Rxjava中最常用的变换,一对一转化

flatMap():一对多转化。

Observable.from(ex:实体类数组studentArr)

                .flatMap(new Func1>(){

        @Override

        public Observable<课程> call(Student student){

            return    Observable.from(student.get课程);         

    }

}).subscribe(new Subscriber<课程>(){

    onNext方法中打印学生所有课程信息;

});

flatMap()和map()两个方法都是把传入的参数转化之后返回另一个对象,不同的是,flatMap()返回的是一个Observable对象,并且这个Observable对象不是直接发送到Subscriber的回调方法中。

flatMap原理:

1.使用传入的事件对象创建一个Observable对象。

2.不发送这个Observable对象而是将它激活,于是开始发送事件。

3.每一个创建出来的Observable发送的事件,都被汇入同一个Observable,并且这个Observable负责将这些事件通给交给Subscriber的回调方法中。

这三个步骤将事件拆分成两级,通过一组新创建的Observable将初始的对象【铺平】,铺平之后统一路径分发下去。flat:平的,铺平  

变换的原理

针对事件序列的处理和再发送,Rxjava内部基于同一个基础变换方法 lift(Operator);

........


5.线程控制--Scheduler(二)

可以多次切换线程。observeOn() 指定的是它之后的操作所在的线程。

Observable.just(1,2,3,4).subscribeOn(Schedulers.io())// IO 线程,由 subscribeOn() 指定

                    .observeOn(Schedulers.newThread())

                    .map(mapOperator)// 新线程,由 observeOn() 指定

                    .observeOn(Schedulers.io())

                    .map(mapOperator2)// IO 线程,由 observeOn() 指定

                    .observeOn(AndroidSchedulers.mainThread())

                    .subscribe(subscriber);// Android 主线程,由 observeOn() 指定

如上,通过 observeOn() 的多次调用,程序实现了线程的多次切换。

不过,不同于 observeOn() , subscribeOn() 的位置放在哪里都可以,但它是只能调用一次的。


你可能感兴趣的:(Rxjava总结)