How to stop and resume Observable.interval emiting ticks

后端 未结 7 2011
野性不改
野性不改 2020-12-13 06:32

This will emit a tick every 5 seconds.

Observable.interval(5, TimeUnit.SECONDS, Schedulers.io())
            .subscribe(tick -> Log.d(TAG, "tick = &qu         


        
相关标签:
7条回答
  • 2020-12-13 07:13

    @AndroidEx , that's a wonderful answer. I did it a bit differently:

    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.
    }
    }
    
    }
    
    0 讨论(0)
  • 2020-12-13 07:14

    Sorry this is in RxJS instead of RxJava, but the concept will be the same. I adapted this from learn-rxjs.io and here it is on codepen.

    The idea is that you start out with two streams of click events, startClick$ and stopClick$. Each click occurring on the stopClick$ stream get mapped to an empty observable, and clicks on startClick$ each get mapped to the interval$ stream. The two resulting streams get merge-d together into one observable-of-observables. In other words, a new observable of one of the two types will be emitted from merge each time there's a click. The resulting observable will go through switchMap, which starts listening to this new observable and stops listening to whatever it was listening to before. Switchmap will also start merge the values from this new observable onto its existing stream.

    After the switch, scan only ever sees the "increment" value emitted by interval$, and it doesn't see any values when "stop" has been clicked.

    And until the first click occurs, startWith will start emitting values from $interval, just to get things going:

    const start = 0;
    const increment = 1;
    const delay = 1000;
    const stopButton = document.getElementById('stop');
    const startButton = document.getElementById('start');
    const startClick$ = Rx.Observable.fromEvent(startButton, 'click');
    const stopClick$ = Rx.Observable.fromEvent(stopButton, 'click');
    const interval$ = Rx.Observable.interval(delay).mapTo(increment);
    const setCounter = newValue => document.getElementById("counter").innerHTML = newValue;
    setCounter(start);
    
    const timer$ = Rx.Observable
    
        // a "stop" click will emit an empty observable,
        // and a "start" click will emit the interval$ observable.  
        // These two streams are merged into one observable.
        .merge(stopClick$.mapTo(Rx.Observable.empty()), 
               startClick$.mapTo(interval$))
    
        // until the first click occurs, merge will emit nothing, so 
        // use the interval$ to start the counter in the meantime
        .startWith(interval$)
    
        // whenever a new observable starts, stop listening to the previous
        // one and start emitting values from the new one
        .switchMap(val => val)
    
        // add the increment emitted by the interval$ stream to the accumulator
        .scan((acc, curr) => curr + acc, start)
    
        // start the observable and send results to the DIV
        .subscribe((x) => setCounter(x));
    

    And here's the HTML

    <html>
    <body>
      <div id="counter"></div>
      <button id="start">
        Start
      </button>
      <button id="stop">
        Stop
      </button>
    </body>
    </html>
    
    0 讨论(0)
  • 2020-12-13 07:15

    Some time ago, I was also looking for kind of RX "timer" solutions, but non of them met my expectations. So there you can find my own solution:

    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);
    }
    
    0 讨论(0)
  • 2020-12-13 07:26

    Here's one possible solution:

    class TickHandler {
    
        private AtomicLong lastTick = new AtomicLong(0L);
        private Subscription subscription;
    
        void resume() {
            System.out.println("resumed");
            subscription = Observable.interval(5, TimeUnit.SECONDS, Schedulers.io())
                                     .map(tick -> lastTick.getAndIncrement())
                                     .subscribe(tick -> System.out.println("tick = " + tick));
        }
    
        void stop() {
            if (subscription != null && !subscription.isUnsubscribed()) {
                System.out.println("stopped");
                subscription.unsubscribe();
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-13 07:26
    val switch = new java.util.concurrent.atomic.AtomicBoolean(true)
    val tick = new java.util.concurrent.atomic.AtomicLong(0L)
    
    val suspendableObservable = 
      Observable.
        interval(5 seconds).
        takeWhile(_ => switch.get()).
        repeat.
        map(_ => tick.incrementAndGet())
    

    You can set switch to false to suspend the ticking and true to resume it.

    0 讨论(0)
  • 2020-12-13 07:27

    You can use takeWhile and loop until conditions is true

    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()
                }
    
            });
    
    0 讨论(0)
提交回复
热议问题