Rxjava概要
- 当程序进行耗时操作的时候,往往会开启一子线程,通过接口回调来处理结果。但是在实际开发中逻辑业务往往都是很复杂的,所以会形成回调中套回调的地步,因此Rxjava就此而诞生。Rxjava本质上是一个异步操作库。
设计模式
观察者模式
- 对象间存在一对多关系,当一个对象被修改时,则通知依赖它的对象,被观察者决定什么时候去触发事件
- 使用场景
- 一个对象依赖另一个变化而变化
- 更改一个对象时,同时需要连带改变其它对象
- 希望通知对象与被通知对象松散耦合时
Rxjava的观察者模式
- 被观察者
- 观察者
- 订阅
- 事件(响应式编程)
Rxjava使用
- 创建被观察者
- 方式一:create方法
var observable = Observable.create(object :ObservableOnSubscribe<String>{ override fun subscribe(emitter: ObservableEmitter<String>?) { emitter?.onNext("H") emitter?.onNext("I") emitter?.onComplete() } })- 方式二:just方法
var observableJust = Observable.just("H","I")- 方式三:from方法
val parameters = arrayOf("H","I") var observableFromArray = Observable.fromArray(parameters)
- 表示事件顺序发出
- 创建观察者
var observer = object :Observer<String>{ override fun onSubscribe(d: Disposable?) { } override fun onNext(t: String?) { } override fun onError(e: Throwable?) { } override fun onComplete() { } }
onNext方法对应传统观察者模式中的update方法onComplete在没有新的事件通过被观察者发出时执行onError框架异常时触发onSubscribe提供观察者与被观察者取消连接通道
- 订阅
observable.subscribe(observer)
- 通过被
observable观察者调用subscribe方法订阅observer观察者 - 按正常来说应该是观察者订阅被观察者,而Rxjava这样设计是为了便于后面的链式调用
Rxjava源码分析
被观察者Observable的创建
ObservableOnSubscribe是一个接口,在观察者创建时被实例化。里面的subscribe方法提供给订阅调用,方法中emitter发射器永不为空
- 实例化后的
ObservableOnSubscribe被传入create方法后首先进行判空操作,然后主要的是传入创建new ObservableCreate<>(source)对象- 最后在外面实例化后的
ObservableOnSubscribe被赋值给ObservableCreate中的source,在观察者模式中被观察用于通知的方法 RxJavaPlugins.onAssembly理解为代理类就行
- 最后在外面实例化后的
观察者创建以及订阅
-
在
observable.subscribe(observer)方法源码中,可以看到核心的代码是subscribeActual -
由创建被观察者的过程得知
subscribeActual的实现方法是ObservableCreate对象中的subscribeActual方法 -
主要的流程是创建了
CreateEmitter对象以及执行类观察者中的onSubscribe回调,以及被观察者的subscribe回调方法
- 在
CreateEmitter对象中用onNext、onError、tryOnError、onComplete这四个方法,同时可以看出这些方法主要执行观察者observer中的回调,因此这就与观察者observer链接起来了,这个CreateEmitter对象在执行订阅后回调给被观察者Observable,当观察者业务执行emitter?.onNext("H")或emitter?.onComplete()时,实现了通知观察者的功能
小结
- 每到我们调用
observable.subscribe(observer)订阅时,从源码中都会执行source.subscribe(parent),从而我们的被观察者中的subscribe方法就会被回调,从回调接口中得到ObservableEmitter对象进行下一步的onNext、onComplete操作,这样就完成了一次订阅。
操作符
- Rxjava支持变换
- 变换:将事件序列中的对象或整个序列进行加工处理转换成新额序列
map
- 把一个事件转换为另一个事件
map用法
Observable.just("local/image/map.png")
.map(new Function<String, Bitmap>() {
@Override
public Bitmap apply(String filePath) throws Throwable {
return getBitmap(filePath);
}
}).subscribe(new Observer<Bitmap>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull Bitmap bitmap) {
showBitmap(bitmap);
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
});
map源码
- 在源码中可以看出,使用
map方法时主要创建ObservableMap对象
- 从
ObservableMap源码中看出,它的设计模式与之前分析过的被观察者ObservableCreate是大体一样的,把实例化后funtion在这个类中进行赋值 Function接口中有一apply方法,表示接收参数类型为T的参数,返回类型为R的参数,通过Function<? super T, ? extends U>也可以理解为T是输入,U是输出
- 在
subscribe订阅时,就会调用subscribeActual方法 - 注意的是
source.subscribe方法的调用,表示我们通过just创建的被观察者订阅一个新的观察者,也就是ObservableJust对象执行了subscribeActual方法
ObservableJust对象执行subscribeActual方法中的run()包含了observer.onNext(value)等方法,因此就证明了Rxjava通过map()方法链式调用的过程
flatMap
- 将传入对象转换成
Observable对象 - 不直接发送转换后的
Observable对象,而将它激活让它自己开始发送事件 - 每一个创建出来的
Observable发送的事件都被汇入同一个Observable - 与map设计思路大体一致,主要也是订阅时候执行
subscribeActual完成业务
flatMap使用
- 上面分析
map场景时,是将String类型转换成Bitmap类型,而flatMap是将String类型转换成Observable类型
Observable.just("http://www.baidu.com",
"http://www.sina.com",
"http://www.sohu.com")
.flatMap(new Function<String, Observable<String>>() {
@Override
public Observable<String> apply(String s) throws Throwable {
return createObservable(s);
}
}).subscribe(new Observer<String>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull String s) {
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
});
Rxjava线程控制
- 在实际网络请求中往往会有很多耗时操作,这就需要在子线程完成再把结果返回到主线程,从而就涉及到了线程的切换
- Rxjava是线程不变原则,哪个线程产生就在哪个线程消费
- Rxjava通过Schedulers类进行线程调度
Schedulers中线程控制符
Schedulers.newThread()启动新线程,在新线程操作Schedulers.io()执行I/O操作,与newThread()区别在于可以使用无上限线程池,可重用多数控件的线程,效率相对较高Schedulers.computation()用于计算使用Schedulers数AndroidSchedulers.mainThread()切换到主线程也就是UI线程,需要额外导入RxAndroid
Rxjava线程控制方法
subscribeOn()指定观察者指定订阅时观察者所发生的线程,也就是Observer内部onSubscribe激活时所处线程observeOn()事件消费线程
使用分析
Observable.just("H", "E", "L")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull String s) {
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
});
- 表示在I/O线程中发送"H", "E", "L"三个事件,在主线程中消费
observeOn可以多次调用,但subscribeOn只能调用一次,它在observeOn前后都可以- 原因是
subscribeOn通过Observable链式调用方式所以只会生效第一个,而observeOn通过操作符
- 原因是
subscribeOn源码
subscribeOn返回一个Observable被观察者对象,主要的也是创建一个ObservableSubscribeOn对象- 主要是
subscribeActual方法,把观察者包装成SubscribeOnObserver对象,然后通知观察者 - 接下来主要分析
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)))SubscribeTask是一个任务类,在run方法中执行source.subscribe(parent)的订阅,source就是在ObservableSubscribeOn构造方法中传进来的ObservableCreate对象
-
scheduler.scheduleDirect方法中有一重要的成员——Worker,createWorker()的实现方式在IoScheduler中
- 通过pool.get()从缓存工作者池CachedWorkerPool中获取ThreadWorker
- 在
Scheduler类scheduleDirect方法执行w.schedule(task, delay, unit)时执行IoScheduler类中schedule方法,其中主要的是调用了scheduleActual方法
- 创建
ScheduledRunnable对象把Runnable和parent包装起来,parent是一个DisposableContainer对象,保存所有事件是否被切断状态的容器。最后判断是否设置延迟时间,立即执行调用submit()方法,延迟执行调用schedule()方法
observeOn源码
- 在调用
observeOn()方法后通过层层包装后最后会创建ObservableObserveOn对象 - 首先判断调度器是不是
TrampolineScheduler(不进行线程切换立即执行当前代码的调度器) - 判断成立立即执行
source.subscribe(observer) - 判断不成立创建
Worker并传入ObserveOnObserver对象
- 在
ObservableObserveOn中的onNext()、onError()、onComplete()方法都调用了schedule() - 在
schedule()方法中使用了worker.schedule(this)进行了调度实现ObservableObserveOn方法中的Runnable接口, - 这里的
worker是在AndroidSchedulers.mainThread()中创建,内部原理就是Handler的线程切换,所以这也是为什么observeOn()方法可以多次调用的原因
- 在当前
ObserveOnObserver的run()方法中若事件没被融化掉,会执行drainNormal()方法,其中会执行a.onNext()方法,这样就呼应了整个Rxjava链式调用的流程。