0

I'm trying to use RxJava on Android to emit a number after 1 second has passed.

However, only the last item (7) gets emitted.

What am I doing wrong?

private Observable<Integer> getIntegerObservable(){
    return Observable.just(1,2,3,4,5,6,7);
}

getIntegerObservable()
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .debounce(1, TimeUnit.SECONDS)
                    .subscribe(new Observer<Integer>() {
                        @Override
                        public void onSubscribe(Disposable d) {

                        }

                        @Override
                        public void onNext(Integer integer) {
                            textView.setText(textView.getText().toString() + String.valueOf(integer)+"\n");
                        }

                        @Override
                        public void onError(Throwable e) {
                            System.out.println(e.getMessage());
                        }

                        @Override
                        public void onComplete() {

                        }
                    });
stcojo
  • 65
  • 7

2 Answers2

1

The Debounce operator filters out items emitted by the source Observable that are rapidly followed by another emitted item.

In your case numbers 1 through 7 are all emitted within a second. The window specified for debounce is one second. The latest item emitted at the end of one second is 7 and so all the other items are filtered out and you receive 7 as output.

The following image shows a case where 6 items are emitted consecutively within one timeframe. Only the sixth item will pass and others will be filtered. Debounce for 6 items

The following image shows another case where the 6th item is emitted after one timeframe so both 5th and 6th items are emitted while the others are filtered. enter image description here

Hope this helps, try playing with the marble diagram at the documentation site.

Jitendra A
  • 1,568
  • 10
  • 18
1

As the documentation says

Debounce only emit an item from an Observable if a particular timespan has passed without it emitting another item. It filters out items emitted by the source Observable that are rapidly followed by another emitted item.

Since in your case all items are emitted within the time window. Only the latest item gets emmited and all the other items are filtered out.

I guess what you're looking for is Delay

The Delay operator modifies its source Observable by pausing for a particular increment of time (that you specify) before emitting each of the source Observable’s items. This has the effect of shifting the entire sequence of items emitted by the Observable forward in time by that specified increment.

So instead it should look something like this:

getIntegerObservable()
          .delay(1, TimeUnit.SECONDS)
          .subscribeOn(Schedulers.io())
          .observeOn(AndroidSchedulers.mainThread())
          .subscribe(...);

You also should consider calling the delay(..) before the subscribeOn(..) to avoid blocking the main thread

Checkout this article, it explains the difference between subscribeOn and observeOn

UPDATE

You can wrap CountDownTimer in an Obserable. For example:

Observable.create(emitter -> new CountDownTimer(7000, 1000) {

          public void onTick(long millisUntilFinished) {
                 emitter.onNext(millisUntilFinished / 1000);
           }

           public void onFinish() {
                emitter.onComplete();
           }
         }.start())
.doOnNext() //you can log your timer here
.subscribe(); //or here

BONUS (Just for fun :D)

RxJava looks way cooler with java8

Observable.create(this::startCountDownTimer)
       .doOnNext() //use long value
       .map(String::valueOf) //map to string
       .doOnNext() //use string value
       .doOnComplete() //gets called when the timer is up
       .subscribe(this::handleTick, this::handleError);

Count down method

private void startCountDownTimer(ObservableEmitter<Long> emitter) {
    new CountDownTimer(7000, 1000) {
        public void onTick(long millisUntilFinished) {
            emitter.onNext(millisUntilFinished / 1000);
        }

        public void onFinish() {
            emitter.onComplete();
        }
    }.start();
}

Handle Ticking method

private void handleTick(String timer) {
    //Update UI
}

Handle error method

private void handleError(Throwable t) {
    //Log and inform user
}
Muhammad Youssef
  • 373
  • 2
  • 11
  • That doesn't work the way I want, it waits for that time interval then it emits all at once – stcojo Aug 26 '18 at 07:03