Search code examples
javaandroidrx-javapolling

RxJava polling + manual refresh


I have a list a want to refresh every minute. For example the user list here : https://github.com/android10/Android-CleanArchitecture/blob/master/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/GetUserList.java

I add a periodical refresh using repeatWhen :

  public Observable<List<User>> buildUseCaseObservable(Void unused) {
    return this.userRepository
        .users()
        .repeatWhen(new Function<Observable<Object>, ObservableSource<?>>() {
          @Override
          public ObservableSource<?> apply(Observable<Object> objectObservable) throws Exception {
            return objectObservable.delay(1, TimeUnit.MINUTES);
          }
        });
  }

It works fine this way, calling onNext every minute. But if I want to refresh immediately this list (because of user's action or because of a notification), I don't know how to perform that.

Should I cancel/dispose the observable and restart a new one ? Thanks


Solution

  • From your code I understand that the users list is generated and emitted upon subscription.

    Here are some solutions I can think of, instead of unsubscribing and resubscribing upon the event to which you want to react immediately:

    1. Instead of using the repeatWhen operator, use the interval creation operator combined with the flatMap to invoke the subscription to a new Observable every minute and use the merge operator to add reaction to the other event in which you are interested. Something like this:

      @Test
      public void intervalObservableAndImmediateReaction() throws InterruptedException {
          Observable<String> obs = Observable.interval(1, TimeUnit.SECONDS)
                      .cast(Object.class)                                          
                      .mergeWith(
                                Observable.just("mockedUserClick")
                                          .delay(500, TimeUnit.MILLISECONDS))
                      .flatMap(
                               timeOrClick -> Observable.just("Generated upon subscription")
                               );
      
          obs.subscribe(System.out::println);
          Thread.currentThread().sleep(3000); //to see the prints before ending the test
      }
      

      or adjusted to your needs (but the principal is the same):

      Observable.interval(1, TimeUnit.MINUTES)
                  .mergeWith(RxView.clicks(buttonView))
                  .flatMap(timeOrClick -> this.userRepository.users());
      
    2. You can use the flatMap operator as before, even while keeping you working current implementation and without merging to an interval - just keep your working code and in another area of the programme chain it to the RxBinding of your choosing:

      RxView.touches(yourViewVariable)
            .flatMatp(motionEvent -> this.userRepository.users())
            .subscribe(theObserver);
      

      Note that in this solution the subscription is done independently to the two observables. You'll probably be better off if you use different observers, or manage a subject or something on that line. A small test I ran showed one subscriber handled subscribing to 2 different observables with no problem (in Rxjava1 - didn't check in Rxjava2 yet), but it feels iffy to me.