Rxbinding使用案例及分析

前言

当今天下,黄巾贼起,狼烟四顾……咳,不好意思剧本拿错了。当今天下,Rxjava异军突起,凭借其简洁明了过程可控的链式编程,和强大的操作符,深受广大开发者青睐,同时也出现很多Rx相关库,如Rxbinding、RxPermission等,还有常用的RxBus(这个不是库)。今天就来介绍一下Rxbinding的使用以及一些实用案例。

简介

RxBinding在Github上的介绍只有一句话:

RxJava binding APIs for Android UI widgets from the platform and support libraries.

用于绑定Android UI控件响应的Rxjava API。下面看个示例就了然了。目前最新版本为2.1.1,本篇示例也是基于此版本。

引入:

implementation ‘com.jakewharton.rxbinding2:rxbinding:2.1.1’

实用场景

1,按钮防抖动

业务中经常有这种问题,点击某个按钮访问网络或跳转页面等,如果每次点击都响应,用户在快速点击时会出现过于频繁访问网络或者页面多次跳转,这时候就需要做按钮防抖动。传统的实现方式是记录每次点击时的时间戳,下次点击时与上次时间比对,如果时间差小于设定的值就不响应。而使用Rxbinding的方式简单明了:
 

RxView.clicks(btnTest)
            //1s内只发射第一个响应事件,过滤掉后面的
            .throttleFirst(1, TimeUnit.SECONDS)
            .subscribe(new Consumer() {
                @Override
                public void accept(Object o) throws Exception {
                    System.out.println("click");
                }
            });    
 
  

2,EditText监听防抖动

在做实时搜索功能时,需要监听用户输入内容实时搜索。如果用户每输入一个字符就访问一次网络,用户输入过快的情况下,会瞬间创建多个网络请求,很容易导致数据错乱,而且输入过快情况下,完全可以过滤掉前面的访问事件,只进行最后一次访问。如下:

RxTextView.textChanges(editText)
            //收到监听事件600ms内没有下一个事件发来时,发送此事件
            .debounce(600, TimeUnit.MILLISECONDS)
            //当有多个网络请求时,以最后一个发送的请求为准,会取消掉之前执行中的请求
            //常与debounce配合使用,防止数据出错
            .switchMap(new Function>() {
                @Override
                public ObservableSource apply(CharSequence charSequence) throws Exception {
                    //模拟网络操作,获取数据
                    return Observable.just(1, 2, 3);
                }
            })
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Consumer() {
                @Override
                public void accept(Integer value) throws Exception {
                    System.out.println("accept:" + value);
                }
            });

3,表单验证

用户手机号登录界面经常有这种需求,再输入了手机号和验证码,并且手机号和验证码的长度符合要求时,登录按钮才变成可点击状态。此时使用Rxbinding结合combineLatest操作符搞定。

combineLatest操作符的作用:CombineLatest则在原始的Observable中任意一个发射了数据时发射一条数据。当原始Observables的任何一个发射了一条数据时,CombineLatest使用一个函数结合它们最近发射的数据,然后发射这个函数的返回值。
 

Observable
            .combineLatest(
                    RxTextView.textChanges(etPhone)
                            .map(new Function() {
                                @Override
                                public String apply(CharSequence charSequence) throws Exception {
                                    return String.valueOf(charSequence);
                                }
                            }),
                    RxTextView.textChanges(etPwd)
                            .map(new Function() {
                                @Override
                                public String apply(CharSequence charSequence) throws Exception {
                                    return String.valueOf(charSequence);
                                }
                            }),
                    new BiFunction() {
                        @Override
                        public Boolean apply(String s, String s2) throws Exception {
                            return s.length() == 11 && s2.length() == 6;
                        }
                    })
            .subscribe(new Consumer() {
                @Override
                public void accept(Boolean aBoolean) throws Exception {
                    if (aBoolean){
                        btnLogin.setEnabled(true);
                    }else {
                        btnLogin.setEnabled(false);
                    }
                }
            });

4,轮询

有时候用户某个动作需要触发轮询访问,操作符搞定很方便。关于concatMap和更多变换类操作符介绍,点击这里。

//点击按钮出发轮询,不需要轮询或页面关闭时要注销掉
    Disposable disposable = RxView.clicks(btnTest)
            .concatMap(new Function>() {
                @Override
                public ObservableSource apply(Object o) throws Exception {
                    //从0开始,每隔1s发射一个递增数字
                    return Observable.interval(0, 1, TimeUnit.SECONDS);
                }
            })
            .subscribe(new Consumer() {
                @Override
                public void accept(Long aLong) throws Exception {
                    //轮询访问
                    System.out.println("accept:" + aLong);
                }
            });

5,想要支持更多控件,引入对应支持库

如果想要在更多view上使用Rxbinding,引入对应的支持库即可,如:

对support-v4的支持,引入:

implementation ‘com.jakewharton.rxbinding2:rxbinding-support-v4:2.1.1’

对appcompat-v7的支持,引入:

implementation ‘com.jakewharton.rxbinding2:rxbinding-appcompat-v7:2.1.1’

对design包的支持:

implementation ‘com.jakewharton.rxbinding2:rxbinding-design:2.1.1’

对recyclerview-v7的支持,引入:

implementation ‘com.jakewharton.rxbinding2:rxbinding-recyclerview-v7:2.1.1’

对leanback-v17的支持:

implementation ‘com.jakewharton.rxbinding2:rxbinding-leanback-v17:2.1.1’

源码分析

Rxbinding内容是怎么实现的呢?其实对rxjava熟悉的伙伴,看到使用方式就猜出个一二了。就是对响应事件的封装,生成Observable对象返回,然后就可以使用rxjava强大的操作符进行一系列加工处理了。我们以点击事件为例:

RxView.clicks(btnTest);

看下clicks的实现:

@CheckResult @NonNull
public static Observable clicks(@NonNull View view) {
    checkNotNull(view, "view == null");
    return new ViewClickObservable(view);
}
 
  

第一句是判空,第二句是生成ViewClickObservalbe对象,看到名称应该知道这是一个自定义Observable,我们看下该对象的实现:

final class ViewClickObservable extends Observable {
    private final View view;

    ViewClickObservable(View view) {
        this.view = view;
    }

    @Override protected void subscribeActual(Observer observer) {
        if (!checkMainThread(observer)) {
            return;
        }
        Listener listener = new Listener(view, observer);
        observer.onSubscribe(listener);
        view.setOnClickListener(listener);
    }

    static final class Listener extends MainThreadDisposable implements OnClickListener {
        private final View view;
        private final Observer observer;

        Listener(View view, Observer observer) {
            this.view = view;
            this.observer = observer;
        }

        @Override public void onClick(View v) {
            if (!isDisposed()) {
            observer.onNext(Notification.INSTANCE);
            }
        }

        @Override protected void onDispose() {
            view.setOnClickListener(null);
        }
    }
}
 
  

继承了Observable,在订阅执行的方法subscribeActual里面,设置了监听,该监听实现了OnClickListener接口。所以归根结底还是设置OnClickListener监听。其他方法也都是类似的方式来实现的。明白了原理,如果我们写了一个自定义view,完全可以写出一个相对应功能的Rxbinding出来(提升逼格的好方法)。

你可能感兴趣的:(Android开发)