Java 如何停止和恢复可观测间隔发射滴答声

Java 如何停止和恢复可观测间隔发射滴答声,java,rx-java,rx-android,Java,Rx Java,Rx Android,这将每5秒发出一次滴答声 Observable.interval(5, TimeUnit.SECONDS, Schedulers.io()) .subscribe(tick -> Log.d(TAG, "tick = "+tick)); 要阻止它,你可以使用 Schedulers.shutdown(); 但是,所有的调度程序都停止了,以后不可能恢复滴答声。如何“优雅地”停止并恢复发射?这里有一个可能的解决方案: AtomicLong elap

这将每5秒发出一次滴答声

Observable.interval(5, TimeUnit.SECONDS, Schedulers.io())
            .subscribe(tick -> Log.d(TAG, "tick = "+tick));
要阻止它,你可以使用

Schedulers.shutdown();

但是,所有的调度程序都停止了,以后不可能恢复滴答声。如何“优雅地”停止并恢复发射?这里有一个可能的解决方案:

AtomicLong elapsedTime = new AtomicLong();
AtomicBoolean resumed = new AtomicBoolean();
AtomicBoolean stopped = new AtomicBoolean();

public Flowable<Long> startTimer() { //Create and starts timper
    resumed.set(true);
    stopped.set(false);
    return Flowable.interval(1, TimeUnit.SECONDS)
            .takeWhile(tick -> !stopped.get())
            .filter(tick -> resumed.get())
            .map(tick -> elapsedTime.addAndGet(1000));
}

public void pauseTimer() {
    resumed.set(false);
}

public void resumeTimer() {
    resumed.set(true);
}

public void stopTimer() {
    stopped.set(true);
}

public void addToTimer(int seconds) {
    elapsedTime.addAndGet(seconds * 1000);
}
类处理程序{
私有AtomicLong lastTick=新AtomicLong(0L);
私人认购;
作废简历(){
系统输出打印项次(“恢复”);
订阅=可观察的.interval(5,TimeUnit.SECONDS,Schedulers.io())
.map(勾选->最后勾选.getAndIncrement())
.subscribe(勾选->系统输出打印项次(“勾选=”+勾选));
}
无效停止(){
if(subscription!=null&&!subscription.isunsubscripted()){
系统输出打印项次(“停止”);
订阅。取消订阅();
}
}
}

您可以将
开关设置为
false
以暂停滴答声,将
开关设置为true
以恢复滴答声。

我认为这是另一种方法。
检查源代码时,您将使用SubscribeTimerPeriodic上的类找到interval()。下面是关键代码

@Override
public void call(final Subscriber<? super Long> child) {
    final Worker worker = scheduler.createWorker();
    child.add(worker);
    worker.schedulePeriodically(new Action0() {
        long counter;
        @Override
        public void call() {
            try {
                child.onNext(counter++);
            } catch (Throwable e) {
                try {
                    worker.unsubscribe();
                } finally {
                    Exceptions.throwOrReport(e, child);
                }
            }
        }

    }, initialDelay, period, unit);
}

很抱歉,这是在RxJS而不是RxJava中,但是概念是相同的。我从这里改编了这个,现在开始了

我们的想法是从两个单击事件流开始,
startClick$
stopClick$
。在
stopClick$
流上发生的每次单击都会映射到一个空的可观察对象,然后单击
startClick$
每次都会映射到
interval$
流。这两个结果流将
合并成一个可观察的可观察对象。换句话说,每次单击时,这两种类型中的一种新的可观察对象将从
merge
发出。生成的可观察对象将通过
开关映射
,它开始监听这个新的可观察对象,并停止监听它之前监听的任何内容。Switchmap还将开始将这个新的可观测值合并到其现有流中

切换后,
scan
只会看到由
interval$
发出的“增量”值,而在单击“停止”时不会看到任何值

在第一次单击之前,
startWith
将开始从
$interval
发出值,以使事情顺利进行:

const start=0;
常数增量=1;
常数延迟=1000;
const stopButton=document.getElementById('stop');
const startButton=document.getElementById('start');
const startClick$=Rx.Observable.fromEvent(开始按钮,'click');
const stopClick$=Rx.Observable.fromEvent(停止按钮,'click');
const interval$=Rx.Observable.interval(延迟).mapTo(增量);
const setCounter=newValue=>document.getElementById(“计数器”).innerHTML=newValue;
设置计数器(启动);
常数计时器$=Rx.可观测
//“停止”点击将发出一个空的可见光,
//单击“开始”将发出间隔$observable。
//这两条流合并成一个可观察的流。
.merge(停止单击$.mapTo(Rx.Observable.empty()),
开始单击$.mapTo(间隔$)
//在第一次单击之前,“合并”不会发出任何信息,因此
//同时使用间隔$启动计数器
.startWith(间隔$)
//每当一个新的可观察对象启动时,停止收听前一个
//一个,然后开始从新的发出值
.switchMap(val=>val)
//将区间$stream发出的增量添加到累加器中
.扫描((acc,curr)=>curr+acc,start)
//启动observable并将结果发送给DIV
.订阅((x)=>setCounter(x));
这是HTML


开始
停止

不久前,我也在寻找RX“定时器”解决方案,但没有一个能满足我的期望。因此,您可以在这里找到我自己的解决方案:

AtomicLong elapsedTime = new AtomicLong();
AtomicBoolean resumed = new AtomicBoolean();
AtomicBoolean stopped = new AtomicBoolean();

public Flowable<Long> startTimer() { //Create and starts timper
    resumed.set(true);
    stopped.set(false);
    return Flowable.interval(1, TimeUnit.SECONDS)
            .takeWhile(tick -> !stopped.get())
            .filter(tick -> resumed.get())
            .map(tick -> elapsedTime.addAndGet(1000));
}

public void pauseTimer() {
    resumed.set(false);
}

public void resumeTimer() {
    resumed.set(true);
}

public void stopTimer() {
    stopped.set(true);
}

public void addToTimer(int seconds) {
    elapsedTime.addAndGet(seconds * 1000);
}
AtomicLong elapsedTime=new AtomicLong();
AtomicBoolean=新的AtomicBoolean();
AtomicBoolean stopped=新的AtomicBoolean();
公共可流动startTimer(){//创建并启动timper
恢复。设置(true);
停止。设置(false);
返回可流动。间隔(1,时间单位。秒)
.takeWhile(勾选->!已停止.get())
.filter(勾选->恢复.get())
.map(勾选->elapsedTime.addAndGet(1000));
}
public void pauseTimer(){
恢复。设置(false);
}
公共无效恢复计时器(){
恢复。设置(true);
}
公共无效停止计时器(){
停止。设置(true);
}
public void addToTimer(整数秒){
elapsedTime.addAndGet(秒*1000);
}

您可以使用takeWhile和loop,直到条件为真

Observable.interval(1, TimeUnit.SECONDS)
        .takeWhile {
            Log.i(TAG, " time " + it)
            it != 30L
        }
        .subscribe(object : Observer<Long> {
            override fun onComplete() {
                Log.i(TAG, "onComplete " + format.format(System.currentTimeMillis()))
            }

            override fun onSubscribe(d: Disposable) {
                Log.i(TAG, "onSubscribe " + format.format(System.currentTimeMillis()))
            }

            override fun onNext(t: Long) {
                Log.i(TAG, "onNext " + format.format(System.currentTimeMillis()))
            }

            override fun onError(e: Throwable) {
                Log.i(TAG, "onError")
                e.printStackTrace()
            }

        });
可观测间隔(1,时间单位秒)
1.takeWhile{
Log.i(标记“time”+it)
它!=30L
}
.订阅(对象:观察员){
覆盖有趣的onComplete(){
Log.i(标记“onComplete”+format.format(System.currentTimeMillis()))
}
覆盖订阅的乐趣(d:一次性){
Log.i(标记“onSubscribe”+format.format(System.currentTimeMillis()))
}
覆盖下一个(t:长){
Log.i(标记“onNext”+format.format(System.currentTimeMillis()))
}
覆盖有趣的错误(e:可丢弃){
Log.i(标签“onError”)
e、 printStackTrace()
}
});

@Androidx,这是一个很好的答案。我做的有点不同:

private fun disposeTask() {
    if (disposeable != null && !disposeable.isDisposed)
      disposeable.dispose()
  }

 private fun runTask() {
    disposeable = Observable.interval(0, 30, TimeUnit.SECONDS)
.flatMap {
        apiCall.runTaskFromServer()
.map{

when(it){
is ResponseClass.Success ->{
keepRunningsaidTasks()
}
is ResponseClass.Failure ->{
disposeTask() //this will stop the task in instance of a network failure.
}
}

}

我认为最好的答案应该是这样的:,其中使用了Scan(),因此不需要在外部累积值(如最佳答案中所建议的)异常应该仅用于处理异常事件,而不是实现逻辑!它会创建不必要的对象,计算量大,语法复杂confusing@MathijsSegers如果
Observable.interval(1, TimeUnit.SECONDS)
        .takeWhile {
            Log.i(TAG, " time " + it)
            it != 30L
        }
        .subscribe(object : Observer<Long> {
            override fun onComplete() {
                Log.i(TAG, "onComplete " + format.format(System.currentTimeMillis()))
            }

            override fun onSubscribe(d: Disposable) {
                Log.i(TAG, "onSubscribe " + format.format(System.currentTimeMillis()))
            }

            override fun onNext(t: Long) {
                Log.i(TAG, "onNext " + format.format(System.currentTimeMillis()))
            }

            override fun onError(e: Throwable) {
                Log.i(TAG, "onError")
                e.printStackTrace()
            }

        });
private fun disposeTask() {
    if (disposeable != null && !disposeable.isDisposed)
      disposeable.dispose()
  }

 private fun runTask() {
    disposeable = Observable.interval(0, 30, TimeUnit.SECONDS)
.flatMap {
        apiCall.runTaskFromServer()
.map{

when(it){
is ResponseClass.Success ->{
keepRunningsaidTasks()
}
is ResponseClass.Failure ->{
disposeTask() //this will stop the task in instance of a network failure.
}
}

}