RxJava 入门(四)-- interval()的坑

本文探讨了RxJava中Observable.interval()在Eclipse环境下不起作用的问题,并提供了两种解决方案:一是通过让程序睡眠来等待数据发射;二是使用Schedulers.trampoline()来确保发射操作能在主线程完成现有工作后执行。

大部分的操作及代码都在我上一篇博客中,这一篇我就其中比较蛋疼的问题说一下

转载自一页飘舟大神的博客,Rx博客很全

这里写图片描述

1. Observable.interval()不起作用的解决办法

在Eclipse下测试Rxjava中的操作符interval()时出现了很奇怪的问题,怎么试都不能执行。

原因是我们的操作不是阻塞的:我们创建了一个每隔一段时间就发射数据的 Observable,然后我们注册了一个 Subscriber 来打印收到的数据。这两个操作都是非阻塞的,而 发射数据的计时器是运行在另外一个线程的,但是这个线程不会阻止 JVM 结束当前的程序,所以 如果没有 System.in.read(); 这个阻塞操作,还没发射数据则程序就已经结束运行了。

Observable.interval(1, TimeUnit.SECONDS)
        .subscribe(new Subscriber<Long>() {

            @Override
            public void onCompleted() {
                // TODO Auto-generated method stub
                System.out.println("onCompleted ");
            }

            @Override
            public void onError(Throwable arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onNext(Long arg0) {
                // TODO Auto-generated method stub
                System.out.println("onNext " + arg0);
            }
        });

这段代码在Eclipse下面运行没有达到我们预期的每隔一秒输出一个数字的结果。

怎么解决呢?

去官网找了下原因,也找到了解决方案:
https://github.com/ReactiveX/RxJava/issues/3932

Observable.interval(1, TimeUnit.SECONDS)
        .subscribe(new Subscriber<Long>() {

            @Override
            public void onCompleted() {
                // TODO Auto-generated method stub
                System.out.println("onCompleted ");
            }

            @Override
            public void onError(Throwable arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onNext(Long arg0) {
                // TODO Auto-generated method stub
                System.out.println("onNext " + arg0);
            }
        });

try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

这样就能输出结果了如下所示:

onNext 0
onNext 1
onNext 2
onNext 3
onNext 4
onNext 5
onNext 6

......

让程序沉睡一段时间似乎也不是很完美的解决方案,继续找就找到了如下的解决办法(https://github.com/ReactiveX/RxJava/issues/4132)。

具体原因如下:

When you use the default scheduler (Schedulers.computation()) the observable emits on another thread. If your program exits just after the subscribe then the observable is not given a chance to run. Put in a long sleep just after the subscribe() call and you will see it working.

Observable.interval(1, TimeUnit.SECONDS, Schedulers.trampoline())
        .subscribe(new Subscriber<Long>() {

            @Override
            public void onCompleted() {
                // TODO Auto-generated method stub
                System.out.println("onCompleted ");
            }

            @Override
            public void onError(Throwable arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onNext(Long arg0) {
                // TODO Auto-generated method stub
                System.out.println("onNext " + arg0);
            }
        });

需要注意的是,上面代码中的 Schedulers.trampoline()替换为Schedulers.immediate()也是可以运行的,但是这样做是不安全的。

The immediate() scheduler is not safe for recursive scheduling on the current thread, use trampoline() instead.

Schedulers.computation() 与 Schedulers.trampoline()区别

/**
     * Creates and returns a {@link Scheduler} that executes work immediately on the current thread.
     *
     * @return a {@link Scheduler} that executes work immediately
     */
    public static Scheduler immediate() {
        return rx.internal.schedulers.ImmediateScheduler.INSTANCE;
    }

    /**
     * Creates and returns a {@link Scheduler} that queues work on the current thread to be executed after the
     * current work completes.
     *
     * @return a {@link Scheduler} that queues work on the current thread
     */
    public static Scheduler trampoline() {
        return rx.internal.schedulers.TrampolineScheduler.INSTANCE;
    }

从上面源码可以看出,immediate()方法返回的是ImmediateScheduler类的实例,而trampoline()方法返回的是TrampolineScheduler类的实例。

ImmediateScheduler类的部分源码:

/**
 * Executes work immediately on the current thread.
 */
public final class ImmediateScheduler extends Scheduler {
    public static final ImmediateScheduler INSTANCE = new ImmediateScheduler();

    private ImmediateScheduler() {
        // the class is singleton
    }

从ImmediateScheduler类的官网介绍中可以看出ImmediateScheduler执行在当前main线程。

TrampolineScheduler类的部分源码:

/**
 * Schedules work on the current thread but does not execute immediately. Work is put in a queue and executed
 * after the current unit of work is completed.
 */
public final class TrampolineScheduler extends Scheduler {
    public static final TrampolineScheduler INSTANCE = new TrampolineScheduler();

    @Override
    public Worker createWorker() {
        return new InnerCurrentThreadScheduler();
    }

TrampolineScheduler类的官网介绍中可以看出TrampolineScheduler不会立即执行,当其他排队任务介绍时才执行,当然TrampolineScheduler运行在当前main线程

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值