RxBinding响应控件事件

原创
2016/07/21 14:01
阅读数 282

前面提到了两个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);
		}

	});
}

现在来总结下示例代码执行的流程:

  1. 创建了一个Action1作为Observer,来更新TextView的显示
  2. 创建一个Observable,处理onSubscribe的任务交给TextViewTextOnSubscribe
  3. 调用Observable.subscribe来建立Observer和Observable的联系
  4. 调用TextViewTextOnSubscribe.call
  5. 创建一个TextWatcher来监听EditView的文本变化
  6. EditView的文本变化后,TextWatcher的onTextChanged被调用
  7. 向Observer发送当前的文本,调用Observer提供的onNext,即Action1.call
  8. Action1.callTextView的显示

其他控件的支持应该是类似的。

要使用JakeWharton/RxBinding的话,要熟悉它的命名方式,这样就能很容易找到自己想要的API。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部