出处: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
@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
@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 super T> 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 extends T>):将传入的数组或者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
//onNext
@Override
public void call(String s) { Log.d("zrl", s); }
}
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() 的位置放在哪里都可以,但它是只能调用一次的。