RxJava强大的线程控制

2018-08-29  本文已影响0人  wayDevelop

以Android为例, 一个Activity的所有动作默认都是在主线程中运行的, 比如我们在onCreate中打出当前线程的名字:

Log.w(TAG, "observable-----Thread" + Thread.currentThread().getName());
结果是
observable-----Threadmain

线程控制 —— Scheduler (一)

在不指定线程的情况下, RxJava 遵循的是线程不变的原则,即:在哪个线程调用 subscribe(),就在哪个线程生产事件;在哪个线程生产事件,就在哪个线程消费事件。如果需要切换线程,就需要用到 Scheduler (调度器)。

  1. Scheduler 的 API (一)
    正常情况下, 上游和下游是工作在同一个线程中的, 也就是说上游在哪个线程发事件, 下游就在哪个线程接收事件.
    在RxJava 中,Scheduler ——调度器,相当于线程控制器,RxJava 通过它来指定每一段代码应该运行在什么样的线程。RxJava 已经内置了几个 Scheduler ,它们已经适合大多数的使用场景:
在RxJava中, 已经内置了很多线程选项供我们选择, 例如有

这些内置的Scheduler已经足够满足我们开发的需求, 因此我们应该使用内置的这些选项, 在RxJava内部使用的是线程池来维护这些线程, 所有效率也比较高.

有了这几个 Scheduler ,就可以使用 subscribeOn() 和 observeOn() 两个方法来对线程进行控制了。 * subscribeOn(): 指定 subscribe() 所发生的线程,即 Observable.OnSubscribe 被激活时所处的线程。或者叫做事件产生的线程。 * observeOn(): 指定 Subscriber 所运行在的线程。或者叫做事件消费的线程。

回到RxJava中, 当我们在主线程中去创建一个上游Observable来发送事件, 则这个上游默认就在主线程发送事件.
当我们在主线程去创建一个下游Observer来接收事件, 则这个下游默认就在主线程中接收事件。
但是实际情况是 ,我们更多想要的是这么一种情况, 在子线程中做耗时的操作, 然后回到主线程中来操作UI,

要达到这个目的, 我们需要先改变上游发送事件的线程, 让它去子线程中发送事件, 然后再改变下游的线程, 让它去主线程接收事件. 通过RxJava内置的线程调度器可以很轻松的做到这一点. 接下来看一段代码

 //创建一个下游  观察者Observer
    Observer<Integer> observer = new Observer<Integer>() {
        @Override
        public void onSubscribe(Disposable d) {

        }

        @Override
        public void onNext(Integer value) {
            Log.w(TAG, "" + value);
            Log.d(TAG, "observer thread is : " + Thread.currentThread().getName());

        }

        @Override
        public void onError(Throwable e) {
        }

        @Override
        public void onComplete() {
        }
    };


    //创建一个上游  被观察者 Observable:
    Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
            Log.d(TAG, "Observable thread is : " + Thread.currentThread().getName());
            emitter.onNext(1);
        }
    });

 //建立连接
observable.subscribeOn(Schedulers.newThread())
                   .observeOn(AndroidSchedulers.mainThread())
                   .subscribe(observer);
打印结果
08-29 18:53:38.313 5128-5155/tongxunlu.com.myapplication D/MainActivity: Observable thread is : RxNewThreadScheduler-1
08-29 18:53:38.314 5128-5128/tongxunlu.com.myapplication W/MainActivity: 1
08-29 18:53:38.314 5128-5128/tongxunlu.com.myapplication D/MainActivity: observer thread is : main

可以看到, 上游发送事件的线程的确改变了, 是在一个叫 RxNewThreadScheduler-2的线程中发送的事件, 而下游仍然在主线程中接收事件, 这说明我们的目的达成了, 接下来看看是如何做到的.

和上一段代码相比,这段代码只不过是增加了两行代码:

.subscribeOn(Schedulers.newThread())                                              
.observeOn(AndroidSchedulers.mainThread())

简单的来说, subscribeOn() 指定的是上游发送事件的线程, observeOn() 指定的是下游接收事件的线程.

需要注意的是

举个例子:

 //建立连接
                observable.subscribeOn(Schedulers.newThread())
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .observeOn(Schedulers.io())
                        .subscribe(observer);

这段代码中指定了两次上游发送事件的线程, 分别是newThread和IO线程, 下游也指定了两次线程,分别是main和IO线程. 运行结果为:

08-29 19:02:29.579 5451-5480/tongxunlu.com.myapplication D/MainActivity: Observable thread is : RxNewThreadScheduler-1
08-29 19:02:29.582 5451-5481/tongxunlu.com.myapplication W/MainActivity: 1
08-29 19:02:29.582 5451-5481/tongxunlu.com.myapplication D/MainActivity: observer thread is : RxCachedThreadScheduler-2

可以看到, 上游虽然指定了两次线程, 但只有第一次指定的有效, 依然是在RxNewThreadScheduler 线程中, 而下游则跑到了RxCachedThreadScheduler 中, 这个CacheThread其实就是IO线程池中的一个.

为了更清晰的看到下游的线程切换过程, 我们加点log:

         Observable.create(new ObservableOnSubscribe<Integer>() {
                    @Override
                    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                        Log.d(TAG, "Observable thread is : " + Thread.currentThread().getName());
                        emitter.onNext(1);
                    }
                }).subscribeOn(Schedulers.newThread())
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .doOnNext(new Consumer<Integer>() {
                            @Override
                            public void accept(Integer integer) throws Exception {
                                Log.d(TAG, "After observeOn(mainThread), current thread is: " + Thread.currentThread().getName());
                            }
                        })
                        .observeOn(Schedulers.io())
                        .doOnNext(new Consumer<Integer>() {
                            @Override
                            public void accept(Integer integer) throws Exception {
                                Log.d(TAG, "After observeOn(io), current thread is : " + Thread.currentThread().getName());
                            }
                        })
                        .subscribe(new Consumer<Integer>() {
                            @Override
                            public void accept(Integer integer) throws Exception {
                                Log.d(TAG, "Observer thread is :" + Thread.currentThread().getName());
                                Log.d(TAG, "onNext: " + integer);
                            }
                        });

我们在下游线程切换之后, 把当前的线程打印出来, 运行结果:

D/MainActivity: Observable thread is : RxNewThreadScheduler-1
D/MainActivity: After observeOn(mainThread), current thread is: main
D/MainActivity: After observeOn(io), current thread is : RxCachedThreadScheduler-2
D/MainActivity: Observer thread is :RxCachedThreadScheduler-2
D/MainActivity: onNext: 1

doOnNext官方介绍:

The doOnNext operator is much like doOnEach(Action1) except that the Action that you pass it as a parameter does not accept a Notification but instead simply accepts the emitted item.

可以这么理解:

实践

对于我们Android开发人员来说, 经常会将一些耗时的操作放在后台, 比如网络请求或者读写文件,操作数据库等等,等到操作完成之后回到主线程去更新UI, 有了上面的这些基础, 那么现在我们就可以轻松的去做到这样一些操作.

读写数据库

上面说了网络请求的例子, 接下来再看看读写数据库, 读写数据库也算一个耗时的操作, 因此我们也最好放在IO线程里去进行, 这个例子就比较简单, 直接上代码:

public Observable<List<Record>> readAllRecords() {
        return Observable.create(new ObservableOnSubscribe<List<Record>>() {
            @Override
            public void subscribe(ObservableEmitter<List<Record>> emitter) throws Exception {
                Cursor cursor = null;
                try {
                    cursor = getReadableDatabase().rawQuery("select * from " + TABLE_NAME, new String[]{});
                    List<Record> result = new ArrayList<>();
                    while (cursor.moveToNext()) {
                        result.add(Db.Record.read(cursor));
                    }
                    emitter.onNext(result);
                    emitter.onComplete();
                } finally {
                    if (cursor != null) {
                        cursor.close();
                    }
                }
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
    }
上一篇 下一篇

猜你喜欢

热点阅读