前言
自從用上RxJava后徹底迷上Rx系列響應(yīng)式編程,從本篇開始一起來學(xué)習(xí)一下Rx套餐之一的RxBinding。RxBinding是什么?它是一組開源庫,來自大神Jake Wharton之手,可將Android中各類UI控件的動作事件轉(zhuǎn)換為RxJava中的數(shù)據(jù)流。也就是說使用RxBinding,我們就可以以RxJava的形式來處理UI事件。本篇主要講解其中RxView的相關(guān)View事件如何綁定。
RxBinding中主要包含RxView、RxTextView、RxAdapterView、RxCompoundButton等等。由于全寫一起篇幅太長,我就一篇講解一種了。本系列主要講解以上常用的4種,詳細(xì)內(nèi)容可飛機(jī)到:
依賴
本系列圍繞我自己編寫的RxBindingDemo來進(jìn)行講解,項(xiàng)目中主要使用ButterKnife做View注入,RxBinding做事件綁定。RxBindingDemo代碼在文末有給地址。
注意:RxBinding包中包含RxJava的內(nèi)容,所以就無需再添加RxJava的依賴了。
dependencies {
......
compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
compile 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
}
BaseActivity
相信學(xué)習(xí)過RxJava的碼友一定記得,使用RxJava實(shí)例化的Disposable需在不用時及時銷毀。
由于每個Activity中都寫一套add與clear的方法會造成代碼冗余,所以我將它們封裝到BaseActivity中方便統(tǒng)一對Disposable進(jìn)行管理,以及ButterKnife的統(tǒng)一綁定與解綁。
獻(xiàn)上代碼:
public abstract class BaseActivity extends AppCompatActivity {
public CompositeDisposable mCompositeDisposable;
private Unbinder mUnbinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
mUnbinder = ButterKnife.bind(this);
mCompositeDisposable = new CompositeDisposable();
onViewCreated(savedInstanceState);
}
/**
* 添加訂閱
*/
public void addDisposable(Disposable mDisposable) {
if (mCompositeDisposable == null) {
mCompositeDisposable = new CompositeDisposable();
}
mCompositeDisposable.add(mDisposable);
}
/**
* 取消所有訂閱
*/
public void clearDisposable() {
if (mCompositeDisposable != null) {
mCompositeDisposable.clear();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
clearDisposable();
mUnbinder.unbind();
}
protected abstract int getLayoutId();
protected abstract void onViewCreated(Bundle savedInstanceState);
}
click點(diǎn)擊事件
clicks
RxView.clicks(View view),通過源碼可發(fā)現(xiàn)其內(nèi)部封裝了View.OnClickListener點(diǎn)擊監(jiān)聽,調(diào)用clicks方法返回一個Observable對象,每當(dāng)點(diǎn)擊這個View的時候,該Observable對象就會發(fā)射一個事件,隨即調(diào)用onNext()方法,Observable對應(yīng)的觀察者就可以通過onNext()回調(diào)響應(yīng)此次點(diǎn)擊事件。使用RxBinding還可做到點(diǎn)擊防抖的效果。來看代碼:
addDisposable(RxView.clicks(btnClick)
.throttleFirst(2, TimeUnit.SECONDS)
.subscribe(o -> {
Log.e("rx_binding_test", "clicks:點(diǎn)擊了按鈕:兩秒內(nèi)防抖");
}));
throttleFirst(long windowDuration, TimeUnit unit),設(shè)置一定時間內(nèi)只響應(yīng)首次(throttleFirst)或者末次(throttleLast)的點(diǎn)擊事件。windowDuration為防抖時間,unit為時間單位。調(diào)用這個方法便可防止短時間內(nèi)對View的重復(fù)點(diǎn)擊,本例中設(shè)置的防抖時間為2s。從代碼看來是不是方便又簡潔呢,以往實(shí)現(xiàn)防抖還得添加各種標(biāo)記,忒麻煩。
longClicks
RxView.longClicks(View view),內(nèi)部封裝了View.OnLongClickListener長按監(jiān)聽,原理同上。
addDisposable(RxView.longClicks(btnClick)
.subscribe(o -> {
Log.e("rx_binding_test", "longClicks:長點(diǎn)擊了按鈕");
}));
draw繪制事件
RxView.draws(View view),內(nèi)部封裝了OnDrawListener繪制監(jiān)聽。
//點(diǎn)擊btnDraw調(diào)用viewCanvas的繪制
addDisposable(RxView.clicks(btnDraw)
.throttleFirst(2, TimeUnit.SECONDS)
.subscribe(o -> {
//此處可模擬讓viewCanvas繪制
//viewCanvas.getViewTreeObserver().dispatchOnDraw();
}));
//當(dāng)viewCanvas繪制時觸發(fā)
addDisposable(RxView.draws(viewCanvas)
.subscribe(o -> {
Log.e("rx_binding_test", "draws:viewCanvas繪制了");
}));
drag拖拽事件
RxView.drags(View view),內(nèi)部封裝了OnDragListener拖拽監(jiān)聽。
//當(dāng)btnDraw被拖拽時觸發(fā)
addDisposable(RxView.drags(btnDraw)
.subscribe(o -> {
Log.e("rx_binding_test", "drags:btnDraw被拖拽了");
}));
layoutChange布局改變事件
RxView.layoutChanges(View view),內(nèi)部封裝了OnLayoutChangeListener布局改變監(jiān)聽。
//點(diǎn)擊btnChange改變btn_layout的布局,防抖2s
addDisposable(RxView.clicks(btnChange)
.throttleFirst(2, TimeUnit.SECONDS)
.subscribe(o -> btnLayout.layout(btnLayout.getLeft() - 20,
btnLayout.getTop(), btnLayout.getRight() - 20, btnLayout.getBottom())
));
//btn_layout布局改變時觸發(fā)
addDisposable(RxView.layoutChanges(btnLayout)
.subscribe(o -> {
Log.e("rx_binding_test", "layoutChanges:btnLayout布局改變了");
}));
scrollChange滑動事件
RxView.scrollChangeEvents(View view),內(nèi)部封裝了OnScrollChangeListener滑動監(jiān)聽。
//點(diǎn)擊btnScroll模擬讓btnScrollLayout滑動
addDisposable(RxView.clicks(btnScroll)
.throttleFirst(2, TimeUnit.SECONDS)
.subscribe(o -> {
x += 10;
if (x == 100) {
x = 0;
}
btnScrollLayout.scrollTo(x, 0);
}));
//btnScrollLayout滑動時觸發(fā)
addDisposable(RxView.scrollChangeEvents(btnScrollLayout)
.subscribe(event -> {
Log.e("rx_binding_test", "scrollChangeEvents:btnScrollLayout滑動了:" + event.toString());
}));
View操作
RxView中還封裝了一些常用的例如setVisibility()、setClickable()等View操作。使用起來也很簡單,如下:
addDisposable(RxView.clicks(btnClick)
.throttleFirst(2, TimeUnit.SECONDS)
.subscribe(o -> {
RxView.visibility(btnClick).accept(true);
RxView.clickable(btnClick).accept(true);
RxView.enabled(btnClick).accept(true);
}));
這種操作方法單獨(dú)使用是需要進(jìn)行try-catch的,但還記得RxJava2系列中我們學(xué)習(xí)到,RxJava2的Action與Function的回調(diào)方法中都默認(rèn)throws Exception,RxBinding也是如此。所以在觀察者中調(diào)用就無需try-catch了。
更多的操作可在RxView的源碼中查到,基本上View中有的,J大神都編寫了,膜拜大神。
取消訂閱
最后別忘了在Activity銷毀時對創(chuàng)建的Disposable取消訂閱。Demo中的Act都以BaseActivity為基類,所以就無需再調(diào)用取消訂閱了,BaseActivity已經(jīng)將這些工作做好了。
總結(jié)
RxBinding使用起來非常簡單,RxView中還有attaches、detaches,focusChanges,globalLayouts,hovers,touches等等就不一一演示了,碼友們可自行嘗試。
進(jìn)階中的碼猿一枚,寫的不對的地方歡迎大神們留言指正,有什么疑惑或者建議也可以在我Github上RxBindingDemo項(xiàng)目Issues中提出,我會及時回復(fù)。
附上Demo的地址:
RxBindingDemo
另外:歡迎光臨我的Hexo個人博客:Lei’s Blog