Q:

How to change parameters in retry request after error in RxJava

I send a login request to server with retrofit 2.0, and server return to the client session token, wich I must use in other requests, but this token has limited life-time, and when it is expire 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? 

A:

You can use retryWhen, but the problem is that your retryWhen retry the same observable object that you create in lazy moment.  
Your solution here is use the operator defer to get the host(), since defer it´s not creating the observable when you define it but when it´s consumed by the subscribed. 
Observable.defer(()-> 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());
          }
    });

You can see some examples of retry here https://github.com/politrons/reactive/blob/master/src/test/java/rx/observables/errors/ObservableExceptions.java

A:

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());
      }
});

