RxBinding浅析

Rxjava前一章节重点内容介绍的差不多,现在可以看下Rxbinding重点代码,其实Rxbinding就是将事件发送封装一下;来先看如何使用RxBinding:

    implementation 'com.jakewharton.rxbinding3:rxbinding:3.1.0'
TextView tv = findViewById(R.id.tv);
RxView.clicks(tv).throttleFirst(2,TimeUnit.SECONDS)
                .subscribe(new Consumer<Unit>() {
                    @Override
                    public void accept(Unit unit) throws Exception {
                        Log.d(TAG,"click TextView");
                    }
                });

分析其源码:

@CheckResult
fun View.clicks(): Observable<Unit> {
  return ViewClickObservable(this)
}

private class ViewClickObservable(
  private val view: View
) : Observable<Unit>() {

  override fun subscribeActual(observer: Observer<in Unit>) {
    if (!checkMainThread(observer)) {
      return
    }
    val listener = Listener(view, observer)
    observer.onSubscribe(listener)
    view.setOnClickListener(listener)
  }

  private class Listener(
    private val view: View,
    private val observer: Observer<in Unit>
  ) : MainThreadDisposable(), OnClickListener {

    override fun onClick(v: View) {
      if (!isDisposed) {
        observer.onNext(Unit)
      }
    }

    override fun onDispose() {
      view.setOnClickListener(null)
    }
  }
}

到这里其实已经看出来这里只是将事件发送封装一下调用onSubscribe/onNext事件;
对比下ObservableCreate.java源码基本相同:

public final class ObservableCreate<T> extends Observable<T> {
    final ObservableOnSubscribe<T> source;

    public ObservableCreate(ObservableOnSubscribe<T> source) {
        this.source = source;
    }

    @Override
    protected void subscribeActual(Observer<? super T> observer) {
        CreateEmitter<T> parent = new CreateEmitter<T>(observer);
        observer.onSubscribe(parent);

        try {
            source.subscribe(parent);
        } catch (Throwable ex) {
            Exceptions.throwIfFatal(ex);
            parent.onError(ex);
        }
    }

    static final class CreateEmitter<T>
    extends AtomicReference<Disposable>
    implements ObservableEmitter<T>, Disposable {

        private static final long serialVersionUID = -3434801548987643227L;

        final Observer<? super T> observer;

        CreateEmitter(Observer<? super T> observer) {
            this.observer = observer;
        }

        @Override
        public void onNext(T t) {
            if (t == null) {
                onError(new NullPointerException("onNext called with null. Null values are generally not allowed in 2.x operators and sources."));
                return;
            }
            if (!isDisposed()) {
                observer.onNext(t);
            }
        }

        @Override
        public void onError(Throwable t) {
            if (!tryOnError(t)) {
                RxJavaPlugins.onError(t);
            }
        }

        @Override
        public boolean tryOnError(Throwable t) {
            if (t == null) {
                t = new NullPointerException("onError called with null. Null values are generally not allowed in 2.x operators and sources.");
            }
            if (!isDisposed()) {
                try {
                    observer.onError(t);
                } finally {
                    dispose();
                }
                return true;
            }
            return false;
        }

        @Override
        public void onComplete() {
            if (!isDisposed()) {
                try {
                    observer.onComplete();
                } finally {
                    dispose();
                }
            }
        }

        @Override
        public void setDisposable(Disposable d) {
            DisposableHelper.set(this, d);
        }

        @Override
        public void setCancellable(Cancellable c) {
            setDisposable(new CancellableDisposable(c));
        }

        @Override
        public ObservableEmitter<T> serialize() {
            return new SerializedEmitter<T>(this);
        }

        @Override
        public void dispose() {
            DisposableHelper.dispose(this);
        }

        @Override
        public boolean isDisposed() {
            return DisposableHelper.isDisposed(get());
        }

        @Override
        public String toString() {
            return String.format("%s{%s}", getClass().getSimpleName(), super.toString());
        }
    }

那么这里可以自己去实现一个类似功能,将ObservableCreate#subscribeActual事件创建过程替换为RxView.clicks生成的Observable即可:

public class RxView {
    public static Observable clicks(View view){
        return new ViewClickObservable(view);
    }
}
public class ViewClickObservable extends Observable<Object> {
    private View view;

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

    @Override
    protected void subscribeActual(Observer<? super Object> observer) {
        if (Looper.myLooper()!=Looper.getMainLooper()){
            return;
        }
        Listener listener = new Listener(view,observer);
        observer.onSubscribe(listener);
        view.setOnClickListener(listener);
    }

    private class Listener extends AtomicReference<Disposable>
            implements View.OnClickListener,Disposable {
        private View view;

        private Observer<Object> observer;

        private Object object;

        public Listener(View view, Observer<Object> observer) {
            this.view = view;
            this.observer = observer;
            object = new Object();
        }

        @Override
        public void onClick(View view){
            if (!isDisposed()){
                observer.onNext(object);
            }
        }

        @Override
        public void dispose() {
            view.setOnClickListener(null);
            DisposableHelper.dispose(this);
        }

        @Override
        public boolean isDisposed() {
            return DisposableHelper.isDisposed(get());
        }
    }
}

这里需要注意,可以不用有subcrible过程,因为click事件主要是想调用下游过程,即View#Click-->事件处理,而建立事件监听过程不关心,只要有一个onNext过程即可,这里就可以省去 source.subscribe(parent)过程;

来看代码:

@Override
    protected void subscribeActual(Observer<? super Object> observer) {
        if (Looper.myLooper()!=Looper.getMainLooper()){
            return;
        }
        Listener listener = new Listener(view,observer);
        observer.onSubscribe(listener);
        view.setOnClickListener(listener);
    }

这个Listener就和ObservableCreate#CreateEmitter一样功能,
observer.onSubscribe(listener)方法主要是触发onSubscribe回调,然后可以在其中拿到Dispose去取消事件发送,当然如果不想取消事件发送,这个代码直接去掉都是可以的;
然后建立OnClick监听器,OnClick回调代码以及Dispose代码如下:

 @Override
 public void onClick(View view){
       if (!isDisposed()){
                observer.onNext(object);
       }
 }
 
 @Override
 public void dispose() {
       view.setOnClickListener(null);
       DisposableHelper.dispose(this);
 }

 @Override
 public boolean isDisposed() {
        return DisposableHelper.isDisposed(get());
 }

然后调用如下代码自己就实现了RxBinding功能了:

 //功能防抖       com.mi.learn.rxbinding.RxView.clicks(tv).throttleFirst(2,TimeUnit.SECONDS)
                .subscribe(new Consumer() {
                    @Override
                    public void accept(Object o) throws Exception {
                        Log.d(TAG,"click TextView");
                    }
                });

类似还可以实现一个监听EditText的输入:

//联想搜索     com.mi.learn.rxbinding.RxView.addEditTextChanges(editText).debounce(1,TimeUnit.SECONDS).subscribe(new Consumer<String>() {
            @Override
            public void accept(String string) throws Exception {
                Log.d(TAG,"editextChanges:"+string);
            }
        });
public static Observable addEditTextChanges(EditText editText){
        return new EditTextChangeObservable(editText);
 }
public class EditTextChangeObservable extends Observable<String> {
    private EditText editText;

    public EditTextChangeObservable(EditText editText){
        this.editText = editText;
    }

    @Override
    protected void subscribeActual(Observer<? super String> observer) {
        if (Looper.myLooper() != Looper.getMainLooper()) {
            return;
        }
        EditTextChangeListener listener = new EditTextChangeListener(editText, observer);
        observer.onSubscribe(listener);
        editText.addTextChangedListener(listener);
    }


    private class EditTextChangeListener extends AtomicReference<Disposable>
            implements TextWatcher,Disposable {
        private EditText editText;
        private Observer<? super String> observer;

        public EditTextChangeListener(EditText editText, Observer<? super String> observer) {
            this.editText = editText;
            this.observer = observer;
        }


        @Override
        public void dispose() {
            editText.addTextChangedListener(null);
            DisposableHelper.dispose(this);
        }

        @Override
        public boolean isDisposed() {
            return DisposableHelper.isDisposed(get());
        }

        @Override
        public void beforeTextChanged(java.lang.CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(java.lang.CharSequence s, int start, int before, int count) {
            if (!isDisposed()){
                observer.onNext(s.toString());
            }
        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容