RxBinding 源码路径,这边直接实战进入源码。
val subscribe = button.clicks()
.subscribe {
Toast.makeText(this@RxbindingActivity, "RxbindingActivity", Toast.LENGTH_LONG).show()
}
这是一段 kotlin 代码,button 是在布局中的一个按钮。通过这段代码就可以监听 button 的点击事件。怎么做到的呢?
@CheckResult
fun View.clicks(): Observable<Unit> {
return ViewClickObservable(this)
}
View.clicks() 方法返回 Observable 被观察者,它的方法中创建了 ViewClickObservable。
private class ViewClickObservable(
private val view: View
) : Observable<Unit>() {
}
ViewClickObservable 的构造方法,只有一个参数 View。它继承自 Observable,和前几节说的 Flowable 一致,它必须实现 subscribeActual,subscribeActual 方法肯定在 ViewClickObservable 订阅的时候运行。
override fun subscribeActual(observer: Observer<in Unit>) {
if (!checkMainThread(observer)) {
return
}
val listener = Listener(view, observer)
observer.onSubscribe(listener)
view.setOnClickListener(listener)
}
点击事件不能异步,所以首先检 UI 线程。其次创建 Listener,与传入的 observer 完成订阅。
private class Listener(
private val view: View,
private val observer: Observer<in Unit>
) : MainThreadDisposable(), OnClickListener {
override fun onClick(v: View) {
if (!isDisposed) {
observer.onNext(Unit)
}
}
override fun onDispose() {
view.setOnClickListener(null)
}
}
Listener 中实现了 OnClickListener,实现 onClick,在 onClick 中调用 observer 发射事件。
而继承的另一个 MainThreadDisposable,它其实就是 Disposable,不过实现了 dispose() 函数,下面就是,这里不是流程重点。
if (unsubscribed.compareAndSet(false, true)) {
if (Looper.myLooper() == Looper.getMainLooper()) {
onDispose();
} else {
AndroidSchedulers.mainThread().scheduleDirect(new Runnable() {
@Override public void run() {
onDispose();
}
});
}
}
由此我们可以看出 View.clicks() 流程了:
创建 ViewClickObservable 被观察者,在 ViewClickObservable 中创建 Listener 监听 view 的点击事件以便发射。
我们的观察者之后订阅上 ViewClickObservable,时刻接受发射的点击事件。
普通按钮的点击事件很简单。在 java 中我们使用 RxView.onClick() 方法,实则时 kotlin 函数的在java中的用法。
@file:JvmName("RxView")
@file:JvmMultifileClass
以上的这些代码在 ViewClickObservable.kt 文件中,而加上了 @file:JvmName("注解的名字")注解,在 java 中就可以实现 注解的名字 + 直接调用函数。
很简单吧。
我们经常放置重复点击使用 throttleFirst(),它实际是 RxJava 内部的函数,当按钮被点击时,我们需要判断是否与上次点击点击的时间间隔,然后再去响应按钮的点击事件。这里就不所说了。
看看其他的
View.longClicks()
private class ViewLongClickObservable(): Observable<Unit>()
private class Listener(): MainThreadDisposable(), OnLongClickListener
override fun subscribeActual(observer: Observer<in Unit>) {
val listener = Listener(view, handled, observer)
observer.onSubscribe(listener)
view.setOnLongClickListener(listener)
}
TextView.textChanges()
fun TextView.textChanges(): InitialValueObservable<CharSequence> {
return TextViewTextChangesObservable(this)
}
abstract class InitialValueObservable<T> : Observable<T>()
返回的 InitialValueObservable 也是 Observable 对象。
override fun subscribeListener(observer: Observer<in CharSequence>) {
val listener = Listener(view, observer)
observer.onSubscribe(listener)
view.addTextChangedListener(listener)
}
addTextChangedListener 监听文字变化。
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (!isDisposed) {
observer.onNext(s)
}
}
onTextChanged 中发射。
Rxbinding 相关的操作库基本都是这么实现的,理解了上几篇的RxJava原理,看来离自己写个库也不远了 。
另外,这边总结下常用的 Subject,它既是 Observable,又是 observer 。也就是既可以发送事件,也可以接收事件。
ReplaySubject :无论是在接收到数据前还是数据后订阅,ReplaySubject都会发射所有数据给订阅者。
BehaviorSubject :接受订阅前最后一个数据和订阅后接收到的所有数据。
PublishSubject :仅会向 Observer 释放在订阅之后 Observable 释放的数据。
AsyncSubject :仅释放 Observable 释放的最后一个数据,并且仅在 Observable 完成之后。然而如果当 Observable 因为异常而终止,AsyncSubject 将不会释放任何数据,但是会向 Observer 传递一个异常通知。
SerializedSubject:将 Subject 串行化的方法,所有其他的 Observable 和 Subject 方法都是线程安全的。
UnicastSubject :仅支持订阅一次的 Subject ,如果多个订阅者试图订阅这个 Subject ,若该 subject 未 terminate,将会受到 IllegalStateException ,若已经 terminate,那么只会执行 onError 或者 onComplete 方法。
我们可在自己的程序中创建 Subject,如
val mUserViewStateSubject: BehaviorSubject<RawMessage> = BehaviorSubject.create()
//改变才发送数据
fun observeViewState(): Observable<RawMessage> {
return mUserViewStateSubject.hide().distinctUntilChanged()
}
我在 mvvm 架构中,在 ViewModel 中创建出 BehaviorSubject,并且在 Activity 或 Fragment 中调用 observeViewState
mAiuiViewModel.observeViewState()
.observeOn(RxSchedulers.ui)
.autoDisposable(scopeProvider)
.subscribe(this::onMsgArrived)
在 ViewModel 中数据改变了,通过 mUserViewStateSubject.onNext(xxx) 发射数据。