0. 目錄
- 簡(jiǎn)介
- 好處
- GitHub 地址
- 依賴
- 示例
1. 簡(jiǎn)介
RxBinding 是 Jake Wharton 寫的框架,它的 Api 能夠把 Android 平臺(tái)和兼容包內(nèi)的 UI 控件變?yōu)?Observable 對(duì)象,這樣就可以把 UI 控件的事件當(dāng)做 Rxjava 中的數(shù)據(jù)流來使用了.
2. 好處
- 能對(duì) View 事件使用 Rxjava 的各種操作.
- 提供了與 Rxjava 一致的回調(diào),代碼簡(jiǎn)潔明了.
- 幾乎支持所有的常用控件和事件.
- 每個(gè)庫(kù)還有對(duì)應(yīng)的 Kotlin 支持庫(kù).
3. GitHub 地址
https://github.com/JakeWharton/RxBinding/
4. 依賴
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
5. 示例
用標(biāo)準(zhǔn)簡(jiǎn)潔的實(shí)現(xiàn)方式,作用于整個(gè)App的所有UI事件.
- 點(diǎn)擊事件:
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO
}
});
RxView.clicks(button)
.subscribe(new Consumer<Object>() {
@Override
public void accept(Object o) throws Exception {
// TODO
}
});
- 文本輸入
EditText editText = findViewById(R.id.editText);
editText.addTextChangedListener(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) {
// TODO
}
@Override
public void afterTextChanged(Editable s) {
}
});
RxTextView.textChanges(editText)
.subscribe(new Consumer<CharSequence>() {
@Override
public void accept(CharSequence charSequence) throws Exception {
// TODO
}
});
- 長(zhǎng)點(diǎn)擊事件:
RxView.longClicks(button).subscribe(new Consumer<Object>() {
@Override
public void accept(Object o) throws Exception {
}
// TODO
});
- 防止重復(fù)點(diǎn)擊(弱網(wǎng)絡(luò)環(huán)境下):
加入依賴:
implementation 'com.safframework:saf-rxlifecycle:1.0.0'
RxView.clicks(button)
.compose(useRxViewTransformer(this))
.subscribe(new Consumer<Object>() {
@Override
public void accept(Object o) throws Exception {
// TODO
}
});
/**
* 綁定內(nèi)存泄漏,解決Rxjava內(nèi)存泄漏的問題
* @param targetActivity
* @return
*/
public ObservableTransformer useRxViewTransformer(final AppCompatActivity targetActivity) {
return new ObservableTransformer() {
@Override
public ObservableSource apply(Observable upstream) {
return upstream.compose(preventDuplicateClicksTransformer())
.compose(RxLifecycle.bind(targetActivity).toLifecycleTransformer());
}
};
}
/**
* 防止重復(fù)點(diǎn)擊
*
* @return
*/
public static ObservableTransformer preventDuplicateClicksTransformer() {
return new ObservableTransformer() {
@Override
public ObservableSource apply(Observable upstream) {
return upstream.throttleFirst(1000, TimeUnit.MICROSECONDS);
}
};
}
說明:
① Android App 使用Rxjava 存在一個(gè)缺點(diǎn): 不完整的訂閱會(huì)導(dǎo)致內(nèi)存泄漏.
② 當(dāng)Observable 正在運(yùn)行,Activity或Fragment 銷毀后,其觀察者仍然會(huì)持有對(duì)它的引用,系統(tǒng)無法對(duì)此Activity/Fragment 進(jìn)行垃圾回收.
③ RxLifecycle 可以通過綁定聲明周期的方式,來解決內(nèi)存泄漏的問題.
- 驗(yàn)證碼倒計(jì)時(shí):
RxView.clicks(button)
.throttleFirst(MAX_COUNT_TIME, TimeUnit.SECONDS)
.flatMap(new Function<Object, ObservableSource<Long>>() {
@Override
public ObservableSource<Long> apply(Object o) throws Exception {
// 更新發(fā)送按鈕的狀態(tài),并初始化顯示倒計(jì)時(shí)文字
RxView.enabled(button).accept(false);
RxTextView.text(button).accept("剩余" + MAX_COUNT_TIME + " 秒");
// 返回 n 秒內(nèi)的倒計(jì)時(shí)觀察者對(duì)象
return Observable.interval(1, TimeUnit.SECONDS, Schedulers.io())
.take(MAX_COUNT_TIME);
}
})
// 將遞增數(shù)字替換成遞減的倒計(jì)時(shí)數(shù)字
.map(new Function<Long, Long>() {
@Override
public Long apply(Long aLong) throws Exception {
return MAX_COUNT_TIME - (aLong + 1);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long aLong) throws Exception {
if (aLong == 0){
RxView.enabled(button).accept(true);
RxTextView.text(button).accept("獲取驗(yàn)證碼");
}else{
RxTextView.text(button).accept("剩余"+aLong +" 秒");
}
}
});
- RecyclerView:
implementation 'com.jakewharton.rxbinding2:rxbinding-recyclerview-v7:2.1.1'
// recycerview 當(dāng)前沒有滾動(dòng)
private static final int SCROLL_STATE_IDLE = 0;
// recyclerview 正在被拖動(dòng)
private static final int SCROLL_STATE_DRAGGING = 1;
// 手已經(jīng)離開屏幕,recyclerview正在做動(dòng)畫移動(dòng)到最終位置
private static final int SCROLL_STATE_SETTLING = 2;
RxRecyclerView.scrollStateChanges(recyclerView)
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer scrollState) throws Exception {
Log.d("state",scrollState.toString());
}
});
說明:
- RecyclerView 提供幾個(gè)狀態(tài)的觀察.
① scrollStateChanges 觀察 RecyclerView 的滾動(dòng)狀態(tài).
② scrollEvents 觀察 RecyclerView 的滾動(dòng)事件.
③ childAttachStateChangeEvents 觀察 child view 的 detached 狀態(tài) ,當(dāng) LayoutManager 或者 RecyclerView 認(rèn)為不再需要一個(gè) child view 時(shí),就會(huì)調(diào)用這個(gè)方法. 如果child view 占用資源,則應(yīng)當(dāng)釋放資源.
④ 以上的例子是 對(duì) 滾動(dòng)狀態(tài)的監(jiān)聽. - 以下是對(duì)RecyclerView 點(diǎn)擊事件的監(jiān)聽:
@Override
protected void convert(ViewHolder holder, final String s, int position) {
holder.setText(R.id.text, s);
RxView.clicks(holder.itemView)
.subscribe(new Consumer<Object>() {
@Override
public void accept(Object o) throws Exception {
Toast.makeText(mContext, s, Toast.LENGTH_SHORT).show();
}
});
}
- 表單驗(yàn)證:
public class ValidationResult {
public boolean flag;
public String message;
public ValidationResult() {
flag = true;
message = "";
}
}
final Button button = findViewById(R.id.button);
final EditText edit02 = findViewById(R.id.editText2);
final EditText edit03 = findViewById(R.id.editText3);
Observable<CharSequence> observable_phone = RxTextView.textChanges(edit02);
Observable<CharSequence> observable_password = RxTextView.textChanges(edit03);
Observable.combineLatest(observable_phone, observable_password,
new BiFunction<CharSequence, CharSequence, ValidationResult>() {
@Override
public ValidationResult apply(CharSequence phone, CharSequence passwrod) throws Exception {
if (phone.length() > 0 && passwrod.length() > 0) {
button.setBackground(getResources().getDrawable(R.drawable.shape_login_pressed));
} else {
button.setBackground(getResources().getDrawable(R.drawable.shape_login_normal));
}
ValidationResult validationResult = new ValidationResult();
if (phone.length() == 0) {
validationResult.flag = false;
validationResult.message = "手機(jī)號(hào)碼不能為空";
} else if (phone.length() != 11) {
validationResult.flag = false;
validationResult.message = "手機(jī)號(hào)碼需要11位";
} else if (passwrod.length() == 0) {
validationResult.flag = false;
validationResult.message = "密碼不能為空";
}
return validationResult;
}
}).subscribe(new Consumer<ValidationResult>() {
@Override
public void accept(ValidationResult validationResult) throws Exception {
mReslut = validationResult;
}
});
RxView.clicks(button)
.compose(useRxViewTransformer(this))
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer() {
@Override
public void accept(Object o) throws Exception {
if (mReslut == null) return;
if (mReslut.flag) {
Toast.makeText(MainActivity.this, "success", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, mReslut.message, Toast.LENGTH_SHORT).show();
}
}
});
說明:
① combineLatest 的作用就是將過個(gè)Observable發(fā)射的數(shù)據(jù)組裝起來然后再發(fā)射出來.
② 這里兩個(gè)輸入框只要內(nèi)容發(fā)生變化,就會(huì)發(fā)送 Observable , 此時(shí)我們即可在 BiFunction 中利用驗(yàn)證方法去判斷輸入框中最新的內(nèi)容,最終返回一個(gè)ValidationResult 對(duì)象.
6. 后續(xù)
如果大家喜歡這篇文章解恰,歡迎點(diǎn)贊;如果想看更多 rxjava 方面的技術(shù)涂佃,歡迎關(guān)注稻轨!