目的
相信做过Android开发的同学都在项目中使用过Rxjava这个库,它可以化繁为简,让代码更简洁、更清晰。这篇文章我将简要介绍RxJava的基本原理以及在项目中使用到的一些常用功能。当然,对于RxJava如何使用并不是本文讨论的重点,我主要想由此及彼,探讨我们在碰到一些优秀的三方库的时候,应该怎样去学习,去使用,能够让我们个人的专业技能有所提高。
基本原理
定义
RxJava官网是这样介绍的:
RxJava:a library for composing asynchronous and event-based programs using observable sequences for the Java VM
翻译:RxJava 是一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库
原理
- RxJava: 基于 一种扩展的观察者模式
- RxJava的扩展观察者模式中有4个角色:
角色 | 作用 |
---|---|
被观察者(Observable) | 产生事件 |
观察者(Observer) | 接收事件,并给出响应动作 |
订阅(Subscribe) | 连接 被观察者 & 观察者, 相当于注册监听 |
事件(Event) | 被观察者 & 观察者 沟通的载体 |
- 使用
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
emitter.onNext(1);
emitter.onComplete();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, "accept integer = " + integer);
}
});
- 说明:上面的使用很简单,链式结构,有种一气呵成的感觉,看起来很舒服,其实做了很多事情
- 创建被观察者,发送事件,即emitter.onNext(1),发送了数字1;
- 指定被观察者的执行线程,Schedulers.io();
- 观察者处理接收到的数据;
- 切换线程到主线程,观察者将在主线程处理这些数据。
- 总结
- RxJava一个核心功能就是线程切换,可以看到,使用简单,代码看起来很简洁、明了;
- 链式结构,很熟悉吧,平时我们创建Dialog的时候,就是链接结构;
在项目中的实际应用
所有的库都是以项目的实际需求为导向,如果在项目中没法使用,那这个库就没任何意义了。RxJava也是如此,之所以有这么多人使用,就是因为项目里面很多操作,不管是简单的还是复杂的操作,都可以使用RxJava很简洁的实现,当然,前提是你要熟悉RxJava。
可能大家会有疑问,前面介绍的使用很简单,没什么精彩的地方,不管怎么看,也不像能在项目中大量的使用。是的,如果只是这样,确实没有什么值得推崇的。RxJava强大的地方,不仅在于线程切换的方便,更重要的是,它有非常多的操作符,可以实现项目中比较复杂的操作。关于这些操作符的详细解读,可以阅读我专门写的一篇文章:操作符全解
下面列举一些在项目中使用很多的用例:
1. 功能防抖
- 使用Rxjava很简单,这里可以防止用户点击登录按钮过快,打开多个登录页面的问题
RxView.clicks(layoutLogin)
.throttleFirst(1, TimeUnit.SECONDS)
.subscribe(new Consumer<Unit>() {
@Override
public void accept(Unit unit) throws Exception {
}
});
2. 定时器
- 蓝牙项目使用,延时500ms处理一些事务
Observable.timer(500, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.subscribe(new Consumer<ArrayList<XmBluetoothDeviceInfo>>() {
@Override
public void accept(ArrayList<XmBluetoothDeviceInfo> xmBluetoothDeviceInfos) throws Exception {
DialogManager.getInstance().askForDismiss(dialogController, true);
if (ObjectUtils.isNotEmpty(xmBluetoothDeviceInfos)) {
startDeviceDetails(edrDevice, xmBluetoothDeviceInfos);
} else {
ToastUtils.showShort(StringUtils.getString(R.string.xm_data_error));
finish();
}
}
})
3.监听器
- 在项目中使用最多,替代了以前我们通过Listener的方式处理监听,这里的好处很多:调用方便;线程切换简单;不用处理添加和删除时的同步问题等等
private final PublishSubject mPublishSubject = PublishSubject.create();
public Disposable registerSessionEvent(Consumer<SessionEvent> onNext) {
Disposable disposable = mPublishSubject.observeOn(AndroidSchedulers.mainThread()).subscribe(onNext);
mCompositeDisposable.add(disposable);
return disposable;
}
4.连续点击N次,每次间隔M毫秒。两个操作符搞定,如果自己写的话就比较复杂了。
mCompositeDisposable.add(observable.buffer(observable.debounce(300, TimeUnit.MILLISECONDS))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(units -> {
if (units != null && units.size() >= 5) {
mTestConfigBtn.setVisibility(View.VISIBLE);
DebugConfig.enableDebug();
}
}));
5. RxBus
- 事件总线,可直接代替EventBus、广播的使用,在项目中也是使用的非常多
val d = RxBus.getInstance().register(ChangeBgEvent::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { changeBgEvent -> activity.setTitleColor(changeBgEvent.color) }
以上只是项目中使用到的列举的很少一部分,实际用到了很多。可以看到,它确实用简洁的代码实现了比较复杂的功能,提升了开发效率。
我们应该如何学习
既然三方库能够给我们的开发带来很大的效率提升,我们当然推荐使用。但是如何使用却是值得探讨,是不是只要会用就行了呢?个人觉得绝对不能只是简单的知道它的用法就行,我们不仅要知其然,还要知其所以然,这样才能理解它的原理,使用起来更加得心应手,不至于使用出错,在碰到问题的时候解决起来也更加顺利。
下面是我对于学习使用三方库的一些看法:
熟练基本用法
- 这是最基本的要求。一般三方库都会有使用文档,我们可以通读一遍,也可以在网上看别人写的一些文章,学习别人对于一些用法的理解。
学习源码
这个比较关键,也是个人比较推荐的做法,我们只有看懂了源码,才能理解它的原理,并学习它的一些优秀的框架和设计
- 注释
- 源码里面有对代码的详细解释,还有使用用例,看这些注释加深对接口的理解,有些注释,看一遍就知道使用使用了
* Example usage:
* <pre> {@code
PublishSubject<Object> subject = PublishSubject.create();
// observer1 will receive all onNext and onComplete events
subject.subscribe(observer1);
subject.onNext("one");
subject.onNext("two");
// observer2 will only receive "three" and onComplete
subject.subscribe(observer2);
subject.onNext("three");
subject.onComplete();
// late Observers only receive the terminal event
subject.test().assertEmpty();
} </pre>
- 装饰者模式
- 库里面大量用到了装饰者模式,这是RxJava的核心,也是我们能够很简洁使用的关键。
abstract class AbstractObservableWithUpstream<T, U> extends Observable<U> implements HasUpstreamObservableSource<T> {
/** The source consumable Observable. */
protected final ObservableSource<T> source;
/**
* Constructs the ObservableSource with the given consumable.
* @param source the consumable Observable
*/
AbstractObservableWithUpstream(ObservableSource<T> source) {
this.source = source;
}
@Override
public final ObservableSource<T> source() {
return source;
}
}
- 链式结构
- Rxjava的使用通过链式结构直接完成,简洁明了,对我们平时的代码设计有很好的借鉴意义,下面是蓝牙的同事使用的案例,实现了比较复杂的逻辑(省略了具体实现)
Disposable subscribe = getMaybe(bluetoothDeviceExt)
.map(new Function<TargetResponseWrap, XmHistoryDeviceInfo>() {
@Override
public XmHistoryDeviceInfo apply(TargetResponseWrap targetResponseWrap) throws Exception {
......
}
})
.map(new Function<XmHistoryDeviceInfo, XmBluetoothDeviceInfo>() {
@Override
public XmBluetoothDeviceInfo apply(XmHistoryDeviceInfo xmHistoryDeviceInfo) throws Exception {
......
}
})
.flatMap(new Function<XmBluetoothDeviceInfo, MaybeSource<XmBluetoothDeviceInfo>>() {
@Override
public MaybeSource<XmBluetoothDeviceInfo> apply(final XmBluetoothDeviceInfo deviceInfo) throws Exception {
......
}
})
.doOnSuccess(new Consumer<XmBluetoothDeviceInfo>() {
@Override
public void accept(XmBluetoothDeviceInfo xmBluetoothDeviceInfo) throws Exception {
......
}
})
.doOnSuccess(new Consumer<XmBluetoothDeviceInfo>() {
@Override
public void accept(XmBluetoothDeviceInfo xmBluetoothDeviceInfo) throws Exception {
......
}
})
.flatMap(new Function<XmBluetoothDeviceInfo, MaybeSource<XmBluetoothDeviceInfo>>() {
@Override
public MaybeSource<XmBluetoothDeviceInfo> apply(final XmBluetoothDeviceInfo deviceInfo) throws Exception {
......
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<XmBluetoothDeviceInfo>() {
@Override
public void accept(XmBluetoothDeviceInfo xmBluetoothDeviceInfo) throws Exception {
......
}
});
当然,RxJava里面还有很多值得开发者学习的地方。如果不能理解充分,很可能会误用,在引入项目初期,也有一些使用不当的地方,包括我自己,后面熟悉之后就好多了。
分享总结
- 我们经常说,完成一件事情或任务,要学会总结,这样才能更加深刻。对于我们软件开发者而言也是一样的,学习之后,能够分享,能够总结,其好处不言而喻。
以上是我在项目中使用Rxjava的一些介绍和使用心得。以及由此引出的引入三方库之后,我们应该如何使用和学习的一些粗浅看法。一句话,就是在引入一个库后,能够学习它背后的原理。