Android:RxJava分析

上一篇博客,里面有很多牛人对RxJava分析的博客链接。

RxJava介绍

GitHub 主页上的自我介绍是 “a library for composing asynchronous and event-based programs using observable sequences for the Java VM”(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)

RxJava 的本质可以压缩为异步这一个词。说到根上,它就是一个实现异步操作的库。

RxJava的好处就是简洁,就算在逻辑复杂的情况下,也能让代码一幕了然,代码逻辑清晰。

RxJava原理分析

RxJava的异步实现原理,是观察者模式的一种拓展。

观察者模式

  • 具有观察者对象(A)和关注事件对象对象(B
  • A 需要对 B 的某种变化具有高度敏感,当 B 这中变化发生时 A 对象要立即做出反映
  • A 可以通过注册(Register)或订阅(Subscribe)的方式告诉 B,当 B 发生某种变化是请通知 A(可以参考Android 中 View的点击事件设置setOnClickListener()

RxJava的观察者模式

RxJava 作为一个工具库,使用的就是通用形式的观察者模式。

RxJava也存在Observer(观察者)和 Observable (关注事件对象),ObserverObservable 通过 subscribe() 方法实现订阅关系, 关注事件对象Observable 在发生指定动作的通知观察者 Observer
为了便于理解,Observable (关注事件对象)可以想成关注事件对象,当关注事件发生后此对象立马通知观察者Observer

RxJava除了对应传统的回调onClick()的方法onNext()外,还有onCompleted()onError()

  • onNext():发出一个事件。
  • onCompleted():事件队列完结。RxJava把所有事件当作一个队列,单独处理队列中的每个事件。当不再有新的onNext()发出时,触发此方法。
  • onError():事件队列异常。事件处理过程中出现异常的情况,此方法会触发,同时队列自动结束,不在允许有事件发出。

RxJava基本使用

实现个简单使用测试,将”One”、”Two”、”There”按顺序Toast打印出来。

创建Observable(关注事件对象)

Observable规定了事件触发的顺序方式。下面创建一个关注事件对象对象并定义事件触发规则。

    Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {
        @Override
        public void call(Subscriber<? super String> subscriber) {
            subscriber.onNext("One");
            subscriber.onNext("Two");
            subscriber.onNext("There");
            subscriber.onCompleted();
        }
    });

也可以使用下面的方式获取观察者对象

Observable<String> observable = Observable.just("One", "Two", "There");
String[] words = {"One", "Two", "There"};
Observable<String> observable = Observable.from(words);

这两种方式是系统帮你完成了创建关注事件对象。

    //Observable.just() 调用 Observable.from()
    public static <T> Observable<T> just(T t1, T t2) {
        return from((T[])new Object[] { t1, t2 });
    }
    //Observable.from()
    public static <T> Observable<T> from(T[] array) {
        int n = array.length;
        if (n == 0) {
            return empty();
        } else
        if (n == 1) {
            return just(array[0]);
        }
        //OnSubscribeFromArray 实现了 Observable.OnSubscribe 接口
        //里面制定了简单的onNext()等触发规则
        return create(new OnSubscribeFromArray<T>(array));
    }

创建Observer(观察者)

Observer规定了事件触发后将执行的行为动作

    Observer<String> observer = new Observer<String>() {

        @Override
        public void onCompleted() {
            ZNotify.toast(mContext, "Completed");
        }

        @Override
        public void onError(Throwable e) {
            ZNotify.toast(mContext, "Error");
        }

        @Override
        public void onNext(String s) {
            ZNotify.toast(mContext, "item:" + s);
        }
    };

除了Observer接口外,RxJava还内置了一个实现Observer接口的抽象类:Subscriber,新建Subscriber观察者对象。

    Subscriber<String> subscriber = new Subscriber<String>() {
        @Override
        public void onCompleted() {
            ZNotify.toast(mContext, "Completed");
        }

        @Override
        public void onError(Throwable e) {
            ZNotify.toast(mContext, "Error");
        }

        @Override
        public void onNext(String s) {
            ZNotify.toast(mContext, "item:" + s);
        }
    };

它们基本使用方式是一样的。在RxJava的Subscribe (订阅)过程中,Observer会被先转化为Subscriber再去使用,SubscriberObserver接口进行了一些拓展。

  1. isUnsubscribed():实现Subscription接口。判断当前Observer(观察者)是否取消订阅关系。用来判断是否有关注事件对象持有当前观察者的引用。
  2. unsubscribe():实现Subscription接口。解除订阅关系释放引用,先用isUnsubscribed()判断下。在subscribe()后,Observable持有Subscriber的引用,这个引用不能及时释放会有内存泄漏的危险。所以在合适的地方调用unsubscribe()解除引用。
  3. onStart():新增方法,事件发送前调用,可以进行准备工作。需要注意,此方法不一定在主线程中调用。如果需要指定线程进行准备工作,可以在doOnSubscribe()方法中进行,下面介绍。

实现订阅关系

建立了ObservableObserver对象之后,我们可以调用subscribe() 方法确立它们之间的订阅关系,就可以工作了。

Subscription subscribe = observable.subscribe(observer);

或者

Subscription subscribe = observable.subscribe(subscriber);

通过subscribe() 方法确定订阅关系后会返回Subscription 接口对象subscribe

之前了解到所有的观察者对象在Subscribe (订阅)过程中会先被转化为Subscriber再去使用,Subscriber实现了接口Subscription

我们可以使用返回的Subscription接口对象在需要的时候调用unsubscribe()方法取消订阅关系,避免因为使用RxJava而导致的内存溢出。

RxJava订阅过程分析

上面了解到subscribe()可以传入Observer对象或是Subscriber对象,并且都将转换为Subscriber执行流程。

那我们先看传入Observer对象的流程。

    public final Subscription subscribe(final Observer<? super T> observer) {
        if (observer instanceof Subscriber) {
            //如果传入的Observer对象是Subscriber的实例,强制转换
            return subscribe((Subscriber<? super T>)observer);
        }
        //新建ObserverSubscriber对象,而这个类是Subscriber的派生类
        return subscribe(new ObserverSubscriber<T>(observer));
    }

ObserverSubscriber类的源码

public final class ObserverSubscriber<T> extends Subscriber<T> {
    final Observer<? super T> observer;

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

    @Override
    public void onNext(T t) {
        observer.onNext(t);
    }

    @Override
    public void onError(Throwable e) {
        observer.onError(e);
    }

    @Override
    public void onCompleted() {
        observer.onCompleted();
    }
}

所以传入Observer对象都被先转化为Subscriber对象在使用。最后调用的方法和传入Subscriber都是一个方法。

    //返回的是:Subscription,方便 unsubscribe() 取消订阅,避免内存泄漏
    static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {

        //这是一个可选方法,在发送消息之前
        subscriber.onStart();

        //将所有的Subscriber实例变成 SafeSubscriber的实例(--观察者)
        // 里面error、complete 订阅取消操作,相当于触发这两方法时自动取消订阅
        if (!(subscriber instanceof SafeSubscriber)) {
            subscriber = new SafeSubscriber<T>(subscriber);
        }

        try {
            //hook.onSubscribeStart方法返回的是 OnSubscribe 实例
            //此处call(subscriber)方法的调用的是建立关注事件对象实例时,实现的 Observable.OnSubscribe.call(Subscriber) 方法
            //call(Subscriber) 方法将订阅是传入的 Subscriber 传入到 Observable.OnSubscribe.call(Subscriber) 方法中
            //OnSubscribe.call(Subscriber) 事件发送逻辑开始运行。
            //所以RxJava不是在创建的时候发送消息,而是在订阅之后开始发送消息
            hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);
            return hook.onSubscribeReturn(subscriber);
        } catch (Throwable e) {
            if (subscriber.isUnsubscribed()) {
                //已取消订阅的操作
                RxJavaPluginUtils.handleException(hook.onSubscribeError(e));
            } else {
                // 没有取消订阅,此时subscriber 是 SafeSubscriber 的实例
                // subscriber.onError 会调用这个类里面的_onError方法,里面会取消订阅
                subscriber.onError(hook.onSubscribeError(e));
            }
            return Subscriptions.unsubscribed();
        }
    }
  • RxJava 在订阅后开始发送消息
  • 关注事件对象实例创建时,创建的 Observable.OnSubscribe.call(Subscriber)方法里面的 Subscriber 实例,就是 Observable.subscribe(Subscriber) 方法传入的实例,用这个实例调用subscriber.onNext("One")subscriber.onCompleted() 等方法

熟练使用

Subscription subscribe = observable.subscribe(subscriber);

subscriber 实现了onCompleted()onError()onNext() 接口。只要传入实现这三个接口对象,可以不用自己去建立个观察者对象的。


        Action1<String> nextAction = new Action1<String>() {
            @Override
            public void call(String s) {
            }
        };

        Action1<Throwable> errorAction = new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {
            }
        };

        Action0 completedAction = new Action0() {
            @Override
            public void call() {
            }
        };

        // 自动创建 Subscriber, 不必传入三个,但定义的方法还是按顺序来
        // param1 用来定义onNext(),param2 用来定义 onError(),param3 用来定义 onCompleted()
        observable.subscribe(nextAction, errorAction, completedAction);
        observable.subscribe(nextAction, errorAction);
        observable.subscribe(nextAction);

所以在需要将”One”、”Two”、”There”按顺序Toast打印出来。可以使用如下代码

        Observable.just("One", "Two", "There")
                //实现生命周期同步,当前组件生命周期结束时自动取消Observable订阅
                //避免RxJava导致内存泄漏
                .compose(this.<String>bindToLifecycle())
                .subscribe(new Action1<String>() {
                    @Override
                    public void call(String s) {
                        ZNotify.toast(mContext, "item:" + s);
                    }
                });

Action0Action1是RxJava提供的接口,还有Action2Action3ActionX等。Action0只有一个call()无参无返回值方法,刚好 onCompleted() 方法也是无参无返回值的,所以Action0call()取代onCompleted() 的职能。Action1只有一个call(T t)一参无返回值方法,和onError()onNext()一样。

看下怎么个替代

    //Observable.subscribe(Action1) 进来的方法
    public final Subscription subscribe(final Action1<? super T> onNext) {
        //传入的Action1接口对象不能为null
        if (onNext == null) {
            throw new IllegalArgumentException("onNext can not be null");
        }

        //获取默认的 onError 、 onCompleted 动作
        Action1<Throwable> onError = InternalObservableUtils.ERROR_NOT_IMPLEMENTED;
        Action0 onCompleted = Actions.empty();
        //ActionSubscriber 是 Subscriber 的派生类
        //将这三个动作传入 ActionSubscriber  的构造方法创建其实例(观察者),并用这个实例进行了订阅操作
        return subscribe(new ActionSubscriber<T>(onNext, onError, onCompleted));
    }

    //Observable.subscribe(Action1,Action1)进来
    public final Subscription subscribe(final Action1<? super T> onNext, final Action1<Throwable> onError) {
        if (onNext == null) {
            throw new IllegalArgumentException("onNext can not be null");
        }
        if (onError == null) {
            throw new IllegalArgumentException("onError can not be null");
        }

        Action0 onCompleted = Actions.empty();
        return subscribe(new ActionSubscriber<T>(onNext, onError, onCompleted));
    }

    //Observable.subscribe(Action1,Action1,Action0)进来
    public final Subscription subscribe(final Action1<? super T> onNext, final Action1<Throwable> onError, final Action0 onCompleted) {
        if (onNext == null) {
            throw new IllegalArgumentException("onNext can not be null");
        }
        if (onError == null) {
            throw new IllegalArgumentException("onError can not be null");
        }
        if (onCompleted == null) {
            throw new IllegalArgumentException("onComplete can not be null");
        }

        return subscribe(new ActionSubscriber<T>(onNext, onError, onCompleted));
    }

RxJava中的变换功能

  • 变换:就是将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列。

map()

    //将输入的 String 转换为 Bitmap 使用
    Observable.just("picture file path")
            .map(new Func1<String, Bitmap>() {
                @Override
                public Bitmap call(String filePath) {
                    //filePath = "picture file path"
                    return getBitmap4Path(filePath);
                }
            })
            .subscribe(new Action1<Bitmap>() {
                @Override
                public void call(Bitmap bitmap) {
                    //bitmap:从 "picture file path" 图片路径获取的 bitmap 资源
                    showBitmap(bitmap);
                }
            });

可见,在map()方法传入的参数Func1对象中,将传入的 String 转换为 Bitmap ,并在 Action1 中使用了这个Bitmap。
map():直接对事件对象的转换,在RxJava中是最长使用的转换。

FuncXActionX类似,区别是FuncX用来包装含有返回值的方法。
Func1<String, Bitmap>:String 参数,Bitmap是返回值,Func1表示传入一个参数,Func2表示传入两个参数,以此类推。返回值只有一个,由最后一个决定返回值类型。如:Func2<String, String, Bitmap>

flatMap()

现在有需求,有多个学生,每个学生有多个课程,现将所有学生的所有课程打印出来。传入的对象是学生,而我们需要对学生的课程进行操作,所以我们决定用map()转换功能。

    Observable.from(students)
            .map(new Func1<Student, List<Course>>() {
                @Override
                public List<Course> call(Student student) {
                    //进行转换
                    return student.getCourses();
                }
            })
            .subscribe(new Action1<List<Course>>() {
                @Override
                public void call(List<Course> courses) {
                    //遍历
                    for (Course course : courses) {
                        Log.d("xxx", course.getCourseName());
                    }
                }
            });

虽然实现了要求,但看上去有点怪怪的感觉。这个变换功能是不需要的,不用map()变换反而简单点。

    Observable.from(students)
            .subscribe(new Action1<Student>() {
                @Override
                public void call(Student student) {
                    //遍历
                    for (Course course : student.getCourses()) {
                        Log.d("xxx", course.getCourseName());
                    }
                }
            });

顿时觉得对于这种要求使用map()变化,就是脱了裤子放屁。但是不使用变换而用遍历,其实也没必要使用RxJava了,看看使用flatMap()

    //Observable.from() 会创建一个关注事件对象对象,标记为 firstObservable
    Observable.from(students)
            .flatMap(new Func1<Student, Observable<Course>>() {
                @Override
                public Observable<Course> call(Student student) {
                    //返回泛型为Course的观察者实例,标记为tempObservable
                    //Observable.from(List)时会依次返回集合中的元素
                    return Observable.from(student.getCourses());
                }
            })
            .subscribe(new Action1<Course>() {
                @Override
                public void call(Course course) {
                    //直接操作 Course 实例
                    Log.d("xxx", course.getCourseName());
                }
            });

flatMap()返回的是关注事件对象对象而subscribe()操作的是Course实例,这和map()返回的是List<Course>操作的也是List<Course>有区别。

flatMap()的操作原理:

  1. 使用传入的事件对象创建一个tempObservable(关注事件对象,看上),这个对象并没有被发送给firstObservable 去通知subscribe()(观察者)执行,而是将tempObservable 激活并发送事件
  2. 创建出来的tempObservable 发出的事件都会被汇入firstObservable ,在由firstObservable通知观察者执行动作
  3. 然后创建下一个tempObservable 重复操作,直到 onCompleted() onError() 触发取消订阅

代码例子中的执行逻辑

  1. Observable.from(students)建立了firstObservable
  2. return Observable.from(student.getCourses())建立了tempObservable
  3. tempObservable 发出事件就是依次返回集合中的元素Course对象,没有第三层的Observable
  4. tempObservable 发出的Course对象汇入firstObservable,因为firstObservabletempObservable 的观察者
  5. firstObservable收到事件Course后发送给它的观察者new Action1<Course>()(最后会被包装成Subscriber)进行最后的处理

lift() 变换原理 ???????????????

上诉两个变换虽然功能不同,但他们都是针对事件序列的处理和在发送,在内部的都是基于lift(Operator)变换方法。

简单起见,以单次调用 lift() 的情况分析

    Observable
            //创建第一个 Observable、OnSubscribe 实例
            .create(new Observable.OnSubscribe<String>() {
                @Override
                public void call(Subscriber<? super String> subscriber) {
                }
            })
            //创建第二个 Observable、OnSubscribe 实例
            .lift(new Observable.Operator<String, String>() {
                @Override
                public Subscriber<? super String> call(Subscriber<? super String> subscriber) {
                    return null;
                }
            })
            //使用第二个 Observable 进行订阅操作,整个RxJava链开始运行
            .subscribe(new Subscriber<String>() {
                @Override
                public void onNext(String s) {

                }
                ...
            });

看下 lift() 方法进行的操作

    public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
        return new Observable<R>(new OnSubscribeLift<T, R>(onSubscribe, operator));
    }
  • 利用 onSubscribe 字段属性创建 OnSubscribeLift(实现了接口 OnSubscribe)的实例
  • onSubscribe 是在构造方法里面赋值,此 lift() 方法是第一个 Observable 调用的,所以 onSubscribe是第一个 Observable 的字段属性,Observable.create() 传入的值
  • 利用 OnSubscribeLift 的实例做参数去创建新的 Observable 实例并返回。新建的 Observable.onSubscribe 属性就是此 OnSubscribeLift 实例,当前 lift() 建立的 Observable 实例 调用 lift() 时使用

看看 OnSubscribeLift 类,省略了些容错判断

public final class OnSubscribeLift<T, R> implements OnSubscribe<R> {

    static final RxJavaObservableExecutionHook hook = RxJavaPlugins.getInstance().getObservableExecutionHook();

    // 上(旧)一级 的Observable 的 OnSubscribe 的引用,可以触发上一级 OnSubscribe 的 call() 方法
    final OnSubscribe<T> parent;

    final Operator<? extends R, ? super T> operator;

    //parent:调用 lift() 方法的 Observable 的 onSubscribe 字段,  上(旧)一级 的Observable
    //operator:Observable.Operator实例,是 Func1 的派生类,lift() 方法调用是需要传入并实现其 call() 方法。
    public OnSubscribeLift(OnSubscribe<T> parent, Operator<? extends R, ? super T> operator) {
        this.parent = parent;
        this.operator = operator;
    }

    //下(新)一级  Observable 有本(老一)级的 Observable 的 OnSubscribe 的引用,调用这个引用的 call() 方法触发
    public void call(Subscriber<? super R> o) {
        try {
            //利用  下(新)一级  传入的 Subscriber 实例
            //经过 lift() 方法传入实例实现的 Observable.Operator.call() 方法
            //获取到新的 Subscriber 实例
            Subscriber<? super T> st = hook.onLift(operator).call(o);
            st.onStart();
            //将获取的新的 Subscriber 实例,传入到  上(旧)一级
            //parent: 上(旧)一级 的Observable 的字段属性
            parent.call(st);
        }
    }
}
  • 除开构造方法,就一个 call(Subscriber) 方法,用来实现借口方法 OnSubscribe.call(Subscriber)
  • 这个方法里面建立了新的 Subscriber 实例,并此实例作为参数触发创建上一个 Observable 时实现的 Observable.OnSubscribe.call(Subscriber) 方法
  • call()调用对象和时间: 在这个实例情况相爱,lift()之后执行了 subscribe(),就是用新的 Observable 实例进行了订阅方法,前面了解到订阅方法 subscribe() 会自动触发进行订阅操作的 ObservableonSubscribe 字段的call()方法。
在这个简单情况下的总结分析
  1. 有两个 Observable
  2. 有两个 OnSubscribe
  3. 订阅方法 subscribe() 是新的 Observable 实例调用,触发的 OnSubscribe 是创建新的 Observable 时新建的 OnSubscribelift()时建立的)
  4. 新的 OnSubscribe.call() 方法中,会创建新的 Subscriber 实例,以此为参触发 老的 OnSubscribe.call()(创建第一个Observable时建立的)方法,相当于进行订阅操作

Scheduler 线程控制器

Scheduler认识

Scheduler用来控制代码运行所在线程的东西,RxJava内置了几个Scheduler

  • Schedulers.immediate():直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler。
  • Schedulers.newThread():总是启用新线程,并在新线程执行操作。
  • Schedulers.io():I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。
  • Schedulers.computation():计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
  • AndroidSchedulers.mainThread():它指定的操作将在 Android 主线程运行。需要导入:compile 'io.reactivex:rxandroid:1.2.0'

Scheduler使用

    Observable
            .create(new Observable.OnSubscribe<String>() {
                @Override
                public void call(Subscriber<? super String> subscriber) {
                    //可能进行计算、I/O、网络请求等才做
                }
            })
            // 指定subscribe()发生的线程。 根据操作选择合适的线程
            .subscribeOn(Schedulers.io())

            .observeOn(Schedulers.newThread())
            //运行在新线程,由 observeOn() 指定
            .map(new Func1<String, Integer>() {
                @Override
                public Integer call(String s) {
                    //A操作,需新线程
                    return null;
                }
            })

            .observeOn(Schedulers.computation())
            //运行在计算线程,由 observeOn() 指定
            .map(new Func1<Integer, String>() {
                @Override
                public String call(Integer integer) {
                    //B操作,需计算线程
                    return null;
                }
            })


            .observeOn(AndroidSchedulers.mainThread())
            // 指定 Subscriber(观察者) 的回调发生在主线程
            .subscribe(new Action1<String>() {
                @Override
                public void call(String number) {
                    //C操作,需主线程
                }
            });

上面代码借助Scheduler我们进行了线程的多次切换,由subscribeOn()observeOn()方法设置。

Scheduler原理

要先知道,一条RxJava操作链有多个Observable,因为在调用create()map()subscribeOn()subscribe()等方法时,都会返回一个新的 Observable对象。

原理分析:

  • subscribeOn()
    • 发生在OnSubscribe中,在事件开始发送之前。
    • 从事件发出的开端就造成影响,直到发生进行的切换,即调用 observeOn()
    • observeOn()不同,只能调用一次,无调用位置要求。
  • observeOn()
    • 发生在observeOn()内建的Subscriber中。在它即将给下一级Subscriber发送事件时
    • 影响以后将创建的Subscriber,控制的是后面的线程。
    • 如上:A操作需要在新线程中运行,在A操作进行前使用observeOn()调整线程,同样在B、C操作之前调整线程。

分析
图片

图中共有 5 处含有对事件的操作。
- ①和②:受 subscribeOn() 影响
- ③和④:受第一个 observeOn() 的影响
- ⑤:受第二个 onserveOn() 影响

第二次调用 subscribeOn() (黄色线段),在通知过程中,线程就被第一个 subscribeOn()(红色线段) 截断,因此对整个流程并没有任何影响。

所以多次调用 subscribeOn() 方法,只有第一个能起作用。

RxJava方便快发的小功能

依赖库的导入

//RxJava 依赖库
compile 'io.reactivex:rxjava:1.1.5'
//生命周期和取消订阅控制,解决有RxJava导致的内存泄漏
compile 'com.trello:rxlifecycle:0.4.0'
compile 'com.trello:rxlifecycle-components:0.4.0'
//RxAndroid唯一用处,就是AndroidSchedulers.mainThread在主线程中运行
compile 'io.reactivex:rxandroid:1.2.0'
//用RxJava实现Android中的SharedPreferences
compile 'com.f2prateek.rx.preferences:rx-preferences:1.0.1'

View防抖动点击

RxView.clicks(btnClick)//触发事件的View
                .throttleFirst(3, TimeUnit.SECONDS)//时间数值、单位
                .compose(this.<Void>bindToLifecycle())
                //订阅的事件
                .subscribe(new Action1<Void>() {
                    @Override
                    public void call(Void aVoid) {
                        ZNotify.toast(getMContext(), "this is a message");
                    }
                });

CheckBox状态实时更新

RxCompoundButton.checkedChanges(checkBox)//绑定 CheckBox 控件
                .compose(this.<Boolean>bindToLifecycle())
                .subscribe(new Action1<Boolean>() {
                    @Override
                    public void call(Boolean aBoolean) {
                        //CheckBox 发生改变后的动作
                        btnLogin.setClickable(aBoolean);
                    }
                });

模拟搜索关键字提醒功能


        RxTextView.textChangeEvents(etSearch)
                //每次输入完之后又500毫秒的缓冲时间,默认在computation调度器
                .debounce(500, TimeUnit.MILLISECONDS)
                //指定事件消费线程,这里是主线程
                .observeOn(AndroidSchedulers.mainThread())
                .compose(this.<TextViewTextChangeEvent>bindToLifecycle())
                //观察者收到信息开始处理,此处代表着text文本改变的信息
                .subscribe(new Action1<TextViewTextChangeEvent>() {
                    @Override
                    public void call(TextViewTextChangeEvent textViewTextChangeEvent) {
                        //做你想做的
                    }
                });

Buffer操作符

点击三次按钮发送一次数据

        RxView.clicks(btnBufferCount)//
                .compose(this.<Void>bindToLifecycle())
                .buffer(3)//点击次数
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<List<Void>>() {
                    @Override
                    public void call(List<Void> voids) {
                        ZNotify.toast(getMContext(), getString(R.string.hint_buffer_count));
                    }
                });

对于数据源:{1, 2, 3, 4, 5, 6, 7, 8, 9}
两两打包发送并跳过第三项:{1, 2}、{4, 5}、{7, 8}

Character[] chs = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        Observable.from(chs)//设置数据源
                //每组取两个,第二组从第3个以后开始取(不包含第3个)
                .buffer(2, 3)
                .compose(this.<List<Character>>bindToLifecycle())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<List<Character>>() {
                    @Override
                    public void call(List<Character> characters) {
                        //“每组”都调用一次这个方法,做你想做的
                    }
                });

zip数据合并

Observable
                //模拟读取本地和网络数据,最终将数据合并显示(必须等最慢的获取到数据)
                .zip(query4Location(), query4Net(), new Func2<List<ContacterBean>, List<ContacterBean>, List<ContacterBean>>() {
                    @Override
                    public List<ContacterBean> call(List<ContacterBean> contacterBeen, List<ContacterBean> contacterBeen2) {
                        contacterBeen.addAll(contacterBeen2);
                        return contacterBeen;
                    }
                }).compose(this.<List<ContacterBean>>bindToLifecycle())
                //指定事件发生线程,耗时操作一般放到io线程,比如网络请求的
                .subscribeOn(Schedulers.io())
                //指定事件消费线程
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<List<ContacterBean>>() {
                    @Override
                    public void call(List<ContacterBean> contacterBeen) {
                        //网络数据和本地数据以组合完成
                    }
                });

megre数据合并

        //模拟网络请求中,先显示本地数据,网络数据加载完成后显示网络数据
        Observable.merge(query4Location(), query4Net())
                .compose(this.<List<ContacterBean>>bindToLifecycle())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<List<ContacterBean>>() {
                    @Override
                    public void call(List<ContacterBean> contacterBeen) {
                        showPage(contacterBeen);
                    }
                });

轮训器

        //延时3000 ,每间隔3000,时间单位
        Observable.interval(3000, 3000, TimeUnit.MILLISECONDS)
                //实现生命周期同步,当前组件生命周期结束时自动取消Observable订阅
                .compose(this.<Long>bindToLifecycle())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Long>() {
                    @Override
                    public void call(Long aLong) {
                        //做你想做的
                    }
                });

定时器

        //定时三秒执行
        Observable.timer(3000, TimeUnit.MILLISECONDS)
                .compose(this.<Long>bindToLifecycle())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Long>() {
                    @Override
                    public void call(Long aLong) {
                        //做你想做的
                    }
                });

可连接的SUBJECT

1.建立一个全局的公共变量publishSubject

    public static PublishSubject<String> publishSubject = PublishSubject.create();

2.在一个界面使用两个FrameLayout并显示不同的Fragment对象

TopFragment topFrag = TopFragment.newInstance();
        BottomFragment bottomFrag = BottomFragment.newInstance();
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.fl_top, topFrag, "top")
                .replace(R.id.fl_bottom, bottomFrag, "bottom")
                .commit();

3.TopFragment使用全局公共变量publishSubjectonNext()方法发送信息。

RxPublishSubjectFrag.publishSubject.onNext("message");

4.BottomFragment使用全局公共变量publishSubject订阅事件,获取到TopFragment发送的信息

        RxPublishSubjectFrag.publishSubject.subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                tvResult.setText(s);
            }
        });

RxBus

PublishSubject线程不安全,Subject<Object, Object>是线程安全的。在RxBus中选择使用线程安全的方式。

1.在Activity中建立rxBus自定义类的对象和获取方法

    private RxBus rxBus;

    public RxBus getRxBusSingleton() {
        if (rxBus == null)
            rxBus = new RxBus();
        return rxBus;
    }

2.在发送事件消息的Fragment中使用rxBus对象发送事件消息(RxEvent对象)

rxBus.send(new RxBus.RxEvent(0, "message"));

3.在接收事件消息的Fragment中使用rxBus对象

  • 将普通的 Observable 转换为可连接的 Observable
ConnectableObservable<RxEvent> tapEventEmitter = rxBus.toObserverable().publish();
  • 使用ConnectableObservable对象去订阅事件,获取到RxEvent事件消息

事件发出后立即接受

        tapEventEmitter.compose(this.<RxEvent>bindToLifecycle())
                .subscribe(new Action1<RxEvent>() {
                    @Override
                    public void call(RxEvent event) {
                        if (event.eventKey == 0)
                            _showTapText();
                    }
                });

设置一段缓冲时间,在这段缓冲时间内事件发出后不会立马消费,就是说不会立即回调订阅的Action动作消费事件。

        tapEventEmitter
                //在指定的生命周期方法调用时取消订阅
                .compose(this.<RxEvent>bindUntilEvent(FragmentEvent.DESTROY))
                .publish(new Func1<Observable<RxEvent>, Observable<List<RxEvent>>>() {
                    @Override
                    public Observable<List<RxEvent>> call(Observable<RxEvent> stream) {
                        //设置 1s 的缓冲时间,在这段时间内收到的消息全部放入缓存,等缓冲时间结束后统一发送
                        return stream.buffer(stream.debounce(1, TimeUnit.SECONDS));
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<List<RxEvent>>() {
                    @Override
                    public void call(List<RxEvent> events) {
                        //收到缓冲时间内所有的event事件
                        int size = events.size();
                        RxEvent event = events.get(0);
                        if (event.eventKey == 0)
                            _showTapCount((String) event.eventValue + size);
                    }
                });
  • 可连接的Observable并不在订阅时触发,而需手动调用connect()方法
tapEventEmitter.connect();

RxBus

public class RxBus {

    private final Subject<RxEvent, RxEvent> _busSubject;

    public RxBus() {
        PublishSubject<RxEvent> objectPublishSubject = PublishSubject.create();
        _busSubject = new SerializedSubject<>(objectPublishSubject);
    }

    public void send(RxEvent event) {
        _busSubject.onNext(event);
    }

    public Observable<RxEvent> toObserverable() {
        return _busSubject;
    }

    public boolean hasObservers() {
        return _busSubject.hasObservers();
    }


    public static class RxEvent {
        public int eventKey;
        public Object eventValue;

        public RxEvent(int eventKey, Object eventValue) {
            this.eventKey = eventKey;
            this.eventValue = eventValue;
        }
    }
}

以下功能在项目里面有包含:
- RxJava + OkHttp + GSON 构建请求
- RxJava + Retrofit的使用

项目地址:里面有APP长用到的东西,RxJava的使用里面也有。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值