前面提到了两个RxBinding库。后者已经讲过是实现Model和View之间的单向绑定。前者是今天讨论的内容,JakeWharton/RxBinding能够帮助我们简化对控件操作的响应处理。不仅仅包括控件本身已经提供的一些Listener,还包括对控件属性变化的响应。
- https://github.com/JakeWharton/RxBinding
- https://github.com/ogaclejapan/RxBinding
JakeWharton/RxBinding是对Android控件提供响应式支持的,所以它分为了几个不同的库。com.jakewharton.rxbinding:rxbinding提供对标准的Android控件支持;com.jakewharton.rxbinding:rxbinding-support-v4提供对Support V4库的支持;com.jakewharton.rxbinding:rxbinding-appcompat-v7提供对V7兼容包的支持;com.jakewharton.rxbinding:rxbinding-design提供对Material Design库的支持;com.jakewharton.rxbinding:rxbinding-recyclerview-v7提供对RecycleView的支持。另外每个库还有对应的kotlin扩展支持库,名字以“-kotlin”结尾。
为了分析JakeWharton/RxBinding实现的原理,我们从一个简单的例子开始:
etUIBinding = (EditText) this.findViewById(R.id.et_ui_binding);
tvUIBinding = (TextView) this.findViewById(R.id.tv_ui_binding);
RxTextView.textChanges(etUIBinding).subscribe(new Action1<CharSequence>() {
@Override
public void call(CharSequence charSequence) {
tvUIBinding.setText(charSequence);
}
});
如果是Java8,最后一句可以使用lamba表达式:用tvUIBinding.setText替换掉冗长的匿名对象Action1。
可以猜测,RxTextView.textChanges应该返回了一个Observable。实际上它的类型是Observable<CharSequence>,是调用Observable.create(new TextViewTextOnSubscribe(view))创建的。TextViewTextOnSubscribe继承自Observable.OnSubscribe<CharSequence>,指定了观察者Observer注册时Observable需要执行的操作。
final class TextViewTextOnSubscribe implements Observable.OnSubscribe<CharSequence> {
// EditText继承自TextView,使用TextView还可以让TextView的值的变化被观测到
final TextView view;
TextViewTextOnSubscribe(TextView view) {
this.view = view;
}
// Observer调用subscribe时执行的动作
@Override public void call(final Subscriber<? super CharSequence> subscriber) {
checkUiThread();
// 创建一个检测TextView文本变化的watcher
final TextWatcher watcher = new TextWatcher() {
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(s);
}
}
@Override public void afterTextChanged(Editable s) {
}
};
// 注册watcher作为TextView文本变化时的Listener
view.addTextChangedListener(watcher);
// 每个Subscriber内部都有一个SubscriptionList,其持有LinkedList<Subscription>,
// 可以定义一系列Subscriber unsubscribe时候需要执行的动作。
// 这里用于将watcher从TextView移除
subscriber.add(new MainThreadSubscription() {
@Override protected void onUnsubscribe() {
view.removeTextChangedListener(watcher);
}
});
// 发送一个初始值,其值是当前TextView的值
subscriber.onNext(view.getText());
}
}
得到一个Observable之后,我们就可以调用Observable.subscribe来绑定一个Observer。示例中subscribe的是一个Action1对象,它只对onNext进行相应。示例的Action1对象的功能是更新TextView的显示。
public final Subscription subscribe(final Action1<? super T> onNext) {
if (onNext == null) {
throw new IllegalArgumentException("onNext can not be null");
}
return subscribe(new Subscriber<T>() {
@Override
public final void onCompleted() {
// do nothing
}
@Override
public final void onError(Throwable e) {
throw new OnErrorNotImplementedException(e);
}
@Override
public final void onNext(T args) {
onNext.call(args);
}
});
}
现在来总结下示例代码执行的流程:
- 创建了一个Action1作为Observer,来更新TextView的显示
- 创建一个Observable,处理onSubscribe的任务交给TextViewTextOnSubscribe
- 调用Observable.subscribe来建立Observer和Observable的联系
- 调用TextViewTextOnSubscribe.call
- 创建一个TextWatcher来监听EditView的文本变化
- EditView的文本变化后,TextWatcher的onTextChanged被调用
- 向Observer发送当前的文本,调用Observer提供的onNext,即Action1.call
- Action1.callTextView的显示
其他控件的支持应该是类似的。
要使用JakeWharton/RxBinding的话,要熟悉它的命名方式,这样就能很容易找到自己想要的API。