Call another Retrofit call on Subject emission

折月煮酒 提交于 2019-12-31 05:19:25

问题


I have a following class:

public class SessionStore {
    Subject<Session, Session> subject;

    public SessionStore() {
       subject = new SerializedSubject<>(BehaviorSubject.create(new Session());
    }

    public void set(Session session) {
        subject.onNext(session);
    }

    public Observable<UserSession> observe() {
        return subject.distinctUntilChanged();
    }
}

In activity I observe the session and perform network operation on each change:

private Subscription init() {
    return sessionStore
            .observe()
            .flatMap(new Func1<Session, Observable<Object>>() {
                @Override
                public Observable<Object> call(Session session) {
                    return (session.isValid() 
                       ? retrofitService.getThingForValid()
                       : retrofitService.getThingForInalid())
                       .subscribeOn(Schedulers.io());
                }
            })
            .subscribe(...);
}

Now I have an Okhttp request interceptor, in which I set the session instance from valid to invalid when network response is non 200 code.

This is what happens:

  1. On initial subscription to session store the getThingForValid() is executed, and fails.
  2. OkHttp intercepts the fail and sets new session.
  3. Session store emits a new, now invalid session.
  4. The new emission executes a getThingForInvalid() method.

What is important to know is that this execution happens in the middle of the previous Retrofit call. This is because OkHttp client is wrapped by Retrofit and all interceptors are executed before Retrofit returns.

Having this in mind, you realize that the second call is being executed and processed by Retrofit already, while the first one hasn't finished yet.

  1. As the first call finishes, it throws HttpException because response was non 200 code.
  2. The xception kills the rx stream and with it the second call.

I have tried to ignore this exception in stream but the second call is cancelled by Retrofit anyways.

Do you have any ideas how to make my concept work please?


回答1:


if you get response code 401 in case of token expiration: you need to add Authenticator in to OkHttpClient.Builder

builder.authenticator(new Authenticator() {
            @Override
            public Request authenticate(Route route, Response response) throws IOException {
                final LoginResponse newLoginResponse = refreshTokenClient.refreshToken();
                //save new token locally, if needed
                return response
                        .request()
                        .newBuilder()
                        .removeHeader("Api-Auth-Token") // removing old header
                        .addHeader("Api-Auth-Token", newLoginResponse.getAuthToken())
                        .build();
            }
        });

where

public interface RefreshTokenService {

   @PUT("/api/v1/tokens")
   LoginResponse refreshToken();

 }

But pay attention: this Authenticator will run each time when response code is 401.



来源:https://stackoverflow.com/questions/40762911/call-another-retrofit-call-on-subject-emission

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!