Search code examples
rx-javachaining

RxJava (Android) - Intermediate step on error, retry after error resolution


I am currently trying to get myself into RxJava.


Now I have the following scenario:
I have to authenticate a user.

The steps that I need to do for this are the following:

  1. Try to authenticate user using locally stored token
  2. If authentication fails (due to token expiration) try to get a new token using a locally stored refresh token
  3. Alternatives:
    • On success:
      1. Save the newly fetched token locally
      2. Try to authenticate again, if this fails, show error
    • On failure (because also the refresh token expired): Show login dialog
    • On failure (because of other reasons): Show error

What I have already implemented are 2 Observables, one for the authentication, one for the refresh of the token. Those return 2 different types of results.


I now struggle to chain those into the steps mentioned above. Is there someone that could give me a hint?

Or is this more a case for a separate class to handle this procedure instead of a RxJava chain (because too complex)?


Solution

  • I think this can be done in a simpler way using an error handling operator onErrorResumeNext() which pass control to another Observable rather than invoking onError(), if the observable encounters an error.

    Let's assume your 2 observables are:

    // Assuming authenticate returns an exception of typeA if it fails
    Observable<A> authenticate;
    // returns an exception of typeB if refresh fails
    Observable<B> refresh;
    

    Now let's create another observable using concatMap.

    // Probably you want to emit token from refresh observable. If not,
    // then I hope you will get the idea how it's done. 
    Observable<Object> refreshThenAuthenticate = refresh.concatMap(new Func1<A, Observable<B>>() {
            @Override
            public Observable<A> call(B b) {
                // create an authentication observable using the token
                return createAuthenticateObservable(b.getToken());
            }
    });
    // Above can be written in much simpler form if you use Java 8 lambdas.
    
    
    /* first authenticate will be executed, if it fails then control will
     * go to refreshThenAuthenticate.
     */
    authenticate
    .onErrorResumeNext(refreshThenAuthenticate)
    .subscribe(new Observer<A>() {
                @Override
                public void onCompleted() {
                   // login successful
                }
    
                @Override
                public void onError(Throwable e) {
                    // if e of typeA show login dialog
                    // else do something else
                }
    
                @Override
                public void onNext(A a) {
    
                }
            });