RxBinding概念说明
RxBinding 是 Jake Wharton 的一个开源库,它提供了一套在 Android 平台上的基于 RxJava 的 Binding API。所谓 Binding,就是类似设置 OnClickListener 、设置 TextWatcher 这样的注册绑定对象的 API。
Android 开发中一个比较典型的例子是点击监听器 OnClickListener 。对设置 OnClickListener 来说, View 是被观察者, OnClickListener 是观察者,二者通过 setOnClickListener() 方法达成订阅关系。订阅之后用户点击按钮的瞬间,Android Framework 就会将点击事件发送给已经注册的 OnClickListener 。采取这样被动的观察方式,既省去了反复检索状态的资源消耗,也能够得到最高的反馈速度。
通过 setOnClickListener() 方法,Button 持有 OnClickListener 的引用;当用户点击时,Button 自动调用 OnClickListener 的 onClick() 方法。概念抽象出来就是(Button -> 被观察者、OnClickListener -> 观察者、setOnClickListener() -> 订阅,手指点击onClick() -> 事件)。
若想了解RxJava整个事件流程请参考 RxJava源码深度解析 文章
实例演示
在build.gradle文件中添加依赖
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.2.1'
compile 'com.jakewharton.rxbinding:rxbinding:0.4.0'
添加点击事件
RxView.clicks(mBtn1).throttleFirst(1, TimeUnit.SECONDS).subscribe(new Action1<Void>() {
@Override
public void call(Void aVoid) {
Log.d("rxview_clicks", "btn1");
}
});
给mBtn1按钮设置点击事件,设置点击间隔时间为1秒,只有超过这个时间点击回调的call方法才会执行。
下面是手指连续点击打印的结果(每隔1秒点击才会回调call一次)
11-10 09:57:35.508 4452-4452/com.cn.liuyz.javademo D/rxview_clicks: btn1
11-10 09:57:36.556 4452-4452/com.cn.liuyz.javademo D/rxview_clicks: btn1
11-10 09:57:37.779 4452-4452/com.cn.liuyz.javademo D/rxview_clicks: btn1
RxBinding的clicks源码解析
clicks(View v)方法
给view注册点击事件
public static Observable<Void> clicks(@NonNull View view) {
//检查view是否为空,空直接报异常
checkNotNull(view, "view == null");
return Observable.create(new ViewClickOnSubscribe(view));
}
public static <T> Observable<T> create(OnSubscribe<T> f) {
//f:ViewClickOnSubscribe对象
//RxJavaHooks.onCreate(f)传进入什么返回什么
return new Observable<T>(RxJavaHooks.onCreate(f));
}
protected Observable(OnSubscribe<T> f) {
//把ViewClickOnSubscribe对象赋值给onSubscribe,这里起别名为onSubscribe1,因为后边会用到很多
this.onSubscribe = f;
}
ViewClickOnSubscribe类
ViewClickOnSubscribe(View view) {
//把我们界面的view传进来
this.view = view;
}
clicks方法是在内部创建了ViewClickOnSubscribe对象和Observable对象,在Observable的构造中把ViewClickOnSubscribe对象赋值给onSubscribe,起别名为onSubscribe1。
throttleFirst(long,TimeUnit)方法
throttleFirst() 是设置点击间隔时间,用于去抖动,也就是消除手抖导致的快速连环点击
public final Observable<T> throttleFirst(long windowDuration, TimeUnit unit) {
return throttleFirst(windowDuration, unit, Schedulers.computation());
}
public final Observable<T> throttleFirst(long skipDuration, TimeUnit unit, Scheduler scheduler) {
return lift(new OperatorThrottleFirst<T>(skipDuration, unit, scheduler));
}
OperatorThrottleFirst对象
public OperatorThrottleFirst(long windowDuration, TimeUnit unit, Scheduler scheduler) {
this.timeInMilliseconds = unit.toMillis(windowDuration);
this.scheduler = scheduler;
}
- timeInMilliseconds:等待时间
public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
return create(new OnSubscribeLift<T, R>(onSubscribe, operator));
}
- onSubscribe:就是上边的别名onSubscribe1对象,即ViewClickOnSubscribe
- operator:OperatorThrottleFirst对象
OnSubscribeLift对象
public OnSubscribeLift(OnSubscribe<T> parent, Operator<? extends R, ? super T> operator) {
this.parent = parent;
this.operator = operator;
}
- parent:就是别为onSubscribe1的对象,即ViewClickOnSubscribe
- operator:是OperatorThrottleFirst对象
public static <T> Observable<T> create(OnSubscribe<T> f) {
return new Observable<T>(RxJavaHooks.onCreate(f));
}
protected Observable(OnSubscribe<T> f) {
//把OnSubscribeLift对象赋值给onSubscribe
this.onSubscribe = f;
}
throttleFirst方法是在内部内部创建了OperatorThrottleFirst对象,又把OperatorThrottleFirst对象传给了OnSubscribeLift对象,又把OnSubscribeLift对象传给了Observable对象,又把OnSubscribeLift对象赋值给onSubscribe,这里起别名为onSubscribe2。
subscribe(Action1)订阅
使View和ViewClickOnSubscribe产生订阅关系
public final Subscription subscribe(final Action1<? super T> onNext) {
//判断Action1是否为空
if (onNext == null) {
throw new IllegalArgumentException("onNext can not be null");
}
Action1<Throwable> onError = InternalObservableUtils.ERROR_NOT_IMPLEMENTED;
Action0 onCompleted = Actions.empty();
return subscribe(new ActionSubscriber<T>(onNext, onError, onCompleted));
}
创建ActionSubscriber对象
public ActionSubscriber(Action1<? super T> onNext, Action1<Throwable> onError, Action0 onCompleted) {
this.onNext = onNext;
this.onError = onError;
this.onCompleted = onCompleted;
}
- onNext:我们传入的Action1对象
public final Subscription subscribe(Subscriber<? super T> subscriber) {
return Observable.subscribe(subscriber, this);
}
- subscriber:是ActionSubscriber对象
- this:是通过调用throttleFirst(…)方法返回的Observable对象
static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {
if (subscriber == null) {
throw new IllegalArgumentException("subscriber can not be null");
}
if (observable.onSubscribe == null) {
throw new IllegalStateException("onSubscribe function can not be null.");
}
subscriber.onStart();
//subscriber是ActionSubscriber对象,所以会进入
//转换成安全的SafeSubscriber对象
if (!(subscriber instanceof SafeSubscriber)) {
subscriber = new SafeSubscriber<T>(subscriber);
}
try {
//onObservableStart传进什么返回什么
RxJavaHooks.onObservableStart(observable, observable.onSubscribe).call(subscriber);
return RxJavaHooks.onObservableReturn(subscriber);
} catch (Throwable e) {
.....省略.....
}
}
- observable.onSubscribe:是别名onSubscribe2对象,即OnSubscribeLift对象
这里就是调用OnSubscribeLift的call方法并把ActionSubscriber对象传进去
OnSubscribeLift的call方法
public void call(Subscriber<? super R> o) {
try {
Subscriber<? super T> st = RxJavaHooks.onObservableLift(operator).call(o);
try {
st.onStart();
parent.call(st);
} catch (Throwable e) {
.....省略.....
}
} catch (Throwable e) {
.....省略.....
}
}
- o:是ActionSubscriber对象
- operator:是OperatorThrottleFirst对象
- parent:就是别为onSubscribe1的对象,即ViewClickOnSubscribe
- st:就是通过调用call(o)返回的Subscriber对象
这里是调用OperatorThrottleFirst的call方法并把OperatorThrottleFirst对象传进去,然后再调用ViewClickOnSubscribe的call方法并把st传进去。
现在先看下OperatorThrottleFirst的call方法,稍等再看ViewClickOnSubscribe的call方法
OperatorThrottleFirst的call方法
public Subscriber<? super T> call(final Subscriber<? super T> subscriber) {
return new Subscriber<T>(subscriber) {
.....省略.....
};
}
- subscriber:是ActionSubscriber对象
这里就是给OnSubscribeLift类中call方法内OperatorThrottleFirst.call(o)方法返回一个Subscriber对象。
紧接着看ViewClickOnSubscribe的call方法
public void call(final Subscriber<? super Void> subscriber) {
checkUiThread();//检查是否在UI线程
View.OnClickListener listener = new View.OnClickListener() {
@Override public void onClick(View v) {
if (!subscriber.isUnsubscribed()) {
//调用onNext方法
subscriber.onNext(null);
}
}
};
//设置view的点击监听事件
view.setOnClickListener(listener);
.....省略.....
}
- subscriber:在OperatorThrottleFirst类中创建的Subscriber对象
- view:我们传进来的View
这里首先检查程序运行是否在主线程,然后注册View的点击事件,当点击onClick()事件发生时回调Subscriber的onNext方法
这里回调的onNext方法就是在OperatorThrottleFirst类中创建的Subscriber对象内的onNext方法
public Subscriber<? super T> call(final Subscriber<? super T> subscriber) {
return new Subscriber<T>(subscriber) {//上面就是调用此对象的onNext方法
private long lastOnNext = -1;
.....省略.....
@Override
public void onNext(T v) {
long now = scheduler.now();//获取当前时间
if (lastOnNext == -1 || now - lastOnNext >= timeInMilliseconds) {
lastOnNext = now;
subscriber.onNext(v);
}
}
.....省略.....
};
}
- subscriber:是ActionSubscriber对象
- timeInMilliseconds:我们传入的时间
- v:null
这里就是调用Subscriber的onNext方法,首次点击lastOnNext为-1进入,再次点击则开始判断是否超过了我们传入的时间,超过则再会进去,以此来达到View的多长时间可点击一次。
ActionSubscriber的onNext(v)方法
public void onNext(T t) {
onNext.call(t);
}
- onNext:我们自己创建的Action1对象
这里就回调到我们自己创建的Action1的call方法了。
其他事件用法
只响应首次事件
private Subscription subscription;
private void initClick() {
Action1 action1 = new Action1() {
@Override
public void call(Object o) {
Log.d("rxview_clicks", "btn1");
subscription.unsubscribe();//取消订阅
}
};
subscription = RxView.clicks(mBtn1).throttleFirst(1, TimeUnit.SECONDS).subscribe(action1);
}
longClicks长按事件
RxView.longClicks(mBtn1)
.throttleFirst(5, TimeUnit.SECONDS)
.subscribe(new Action1<Void>() {
@Override
public void call(Void aVoid) {
Log.d("rxview_longClicks", "btn1");
}
});
还有一些layoutChanges(布局变化)、scrollChange(滑动)、draws(绘制)等事件就不做介绍了。