Search code examples
androidretrofit2rx-java2

How to change parameters in retry request after error in RxJava


I send a login request to server with retrofit 2.0, and server returns to the client a session token, which I must use in other requests, but this token has limited life-time, and when it is expires the server returns HTTP error 401.

I try make re-logon, after getting this error, with help a next code:

    holder.getApi(GuideProfileApi.class)
      .getProfile(String.valueOf(holder.getServerId()), holder.getServerToken())
      .subscribeOn(Schedulers.io())
      .retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
         @Override
         public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
           return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
             @Override
             public ObservableSource<?> apply(Throwable throwable) throws Exception {
               if (throwable instanceof HttpException &&  ((HttpException)throwable).code() == 401) {
                 RegistryLoginResult loginResult = holder.login().blockingSingle();
                 return holder.getApi(GuideProfileApi.class)
                    .getProfile(String.valueOf(loginResult.getUserId()), loginResult.getSessionToken());
               }
               return Observable.error(throwable);
            }
        });
     }
  })
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(new Consumer<ProfileResult>() {
    @Override
    public void accept(ProfileResult profileResult) throws Exception {
      Log.d("Result", profileResult.toString());
    }
  }, new Consumer<Throwable>() {
      @Override
      public void accept(Throwable throwable) throws Exception {
        Log.e("Result", throwable.getLocalizedMessage());
      }
});

And retry request is sent, but parameters of request are same as in incorrect request (before re-login). How I can change parameters of the request before sending it again?


Solution

  • You're using the wrong operator. retryWhen will retry your original observable if it encounters an error. What you need is onErrorResumeNext. Something like

     holder.getApi(GuideProfileApi.class)
          .getProfile(String.valueOf(holder.getServerId()), holder.getServerToken())
          .subscribeOn(Schedulers.io())
          .onErrorResumeNext(new Function<Throwable, ObservableSource<?>>() {
            @Override
             public ObservableSource<?> apply(Throwable throwable) {
                   if (throwable instanceof HttpException &&  ((HttpException)throwable).code() == 401) {
                     RegistryLoginResult loginResult = holder.login().blockingSingle();
                     return holder.getApi(GuideProfileApi.class)
                        .getProfile(String.valueOf(loginResult.getUserId()), loginResult.getSessionToken());
                   }
                   return Observable.error(throwable);
            }
        }) 
      .observeOn(AndroidSchedulers.mainThread())
      .subscribe(new Consumer<ProfileResult>() {
        @Override
        public void accept(ProfileResult profileResult) throws Exception {
          Log.d("Result", profileResult.toString());
        }
      }, new Consumer<Throwable>() {
          @Override
          public void accept(Throwable throwable) throws Exception {
            Log.e("Result", throwable.getLocalizedMessage());
          }
    });