在 Android Studio 的 Retrofit2 回调中等待请求

Wait for the request in a Retrofit2 Callback in Android Studio

我尝试在我的应用程序中改进改造请求和自定义回调。当我登录时,我的后端会为用户生成一个令牌。每 X seconds/minutes,我的令牌都会被弃用,当我发出新请求时,我需要 generate/refresh 一个新令牌。

我遇到的问题是当令牌被弃用时,我无法在请求之前生成一个新令牌。

MainActivity.java

ApiService mApiService = RetrofitClientInstance.getRetrofitInstance().create(ApiService.class);

Call < Data > call = mApiService.getData(config.token, params); //My actual token and some custom parameters

call.enqueue(new MyCallback < Data > () {
            @Override
            public void onResponse(Call < Data > call, Response < Data > response) {
                super.onResponse(call, response);
                config.data = response.body(); //configuration class where I store the result of the request
                startActivity(new Intent(this, NewActivity.class);
                }

                @Override
                public void onFailure(Call < Data > call, Throwable t) {
                    super.onFailure(call, t);
                }
            });

MyCallback.java

public class MyCallback < T > implements Callback < T > {

   private String TAG = "MyCallback";
   private ApiService mApiService = ConnectionsRequest.getApiService();
   @Override
   public void onResponse(Call < T > call, Response < T > response) {
       if (new Gson().toJson(response.body()).contains("needrefreshtoken")) {
           Log.i(TAG, "Generate new token");
           mApiService.getRefreshToken(config.login.getRefreshToken()).enqueue(new Callback() {
               @Override
               public void onResponse(Call < RefreshToken > call, Response < RefreshToken > response) {
                   config.token = response.body().getNewToken();
                   Log.i(TAG, "New token generated");
               }

               @Override
               public void onFailure(Call < RefreshToken > call, Throwable t) {
                   super.onFailure(call, t);
               }
           });
       }

   }

   @Override
   public void onFailure(Call < T > call, Throwable t) {
       Log.e(TAG, t.toString());
   }
}

看来我在刷新令牌请求之前(或期间)执行了主要请求。

如何改进我的代码以逐步执行此操作(刷新令牌然后执行主要请求)?

感谢您的帮助。

我们在使用动态 header 集成(令牌)时记住以下事项。

  1. 我们使用应用程序时令牌可能随时过期
  2. api 中的错误 401。

所以我们需要在调用api时检测令牌过期的回调,所以我们使用Authendicator,它会在我们的api得到401时触发(添加验证器class 如果您使用 api).

发送令牌

如果您收到 401,请调用您的刷新 api,然后使用新令牌再次调用您现有的 api。

验证者:

class TokenAuthenticator implements Authenticator {

        @Nullable
        @Override
        public Request authenticate(@NonNull Route route, @NonNull Response response) throws IOException {
           //call your refersh token api 

            //returned new request with updated header
            return response.request().newBuilder()
                    .header("AUTHORIZATION", "new token from refresh token api")
                    .build();
        }
    }

然后将 Authendicator 添加到您的 okhttp 客户端

 .authenticator(new TokenAuthenticator())

所以我找到了一个有效的自定义解决方案。我希望我能帮助人们。 我想尽可能地简化请求,所以这就是 http 请求的样子:

MainActivity.java

@OnClick(R.id.button)
@Optional
void onClickButton()
{
        JsonObject params = new JsonObject();
        params.addProperty("key", "value");

        Call < MyModel > call = myApiService.postCustomRequest(params);
        RetrofitCallback.enqueue(call, new Callback < MyModel >() {
            @Override
            public void onResponse(@NonNull Call<NewIncidentData> call, @NonNull Response<NewIncidentData> response) {
                //Do you stuff here, no need to add custom request code
            }

            @Override
            public void onFailure(@NonNull Call<NewIncidentData> call, @NonNull Throwable t) {
                  //Same here
            }
        });

}

RetrofitCallback.java

public class RetrofitCallback {
    public static <T> void enqueue(Call<T> call, final Callback<T> callback) {
        Log.i(TAG, "HTTP Request : " + call.request().url());
        call.enqueue(new CustomCallback<T>(call) {
            @Override
            public void onResponse(Call<T> call,  Response<T> response) {
                super.onResponse(call, response);
                if(call.isCanceled())
                    return;
                callback.onResponse(call, response);
            }

            @Override
            public void onFailure(Call<T> call, Throwable t) {
                super.onFailure(call, t);
                callback.onFailure(call, t);
            }
        });
    }
}

CustomCallback.java

public class CustomCallback<T> implements Callback<T> {

    private String TAG = "CustomCallback";
    private ApiService mApiService = ConnectionsRequest.getApiService();
    private Config config = Config.getInstance();

    public CustomCallback(Call<T> call) {
        this.call = call;
    }

    @Override
    public void onResponse(Call<T> main_call, Response<T> response) {
        //Check if the token is still valid
        if (new Gson().toJson(response.body()).contains("needrefreshtoken")) {
            Log.i(TAG, "Generate new token");
            main_call.cancel();
            RetrofitCallback.enqueue(mApiService.getToken(config.refreshtoken()), new Callback<TokenModel>() {
                @Override
                public void onResponse(@NonNull Call<TokenModel> call, @NonNull Response<TokenModel> response) {
                    config.token = response.body().getToken();
                    Log.i(TAG, "New token generated and saved");
                    retryMainRequest();
                }

                @Override
                public void onFailure( @NonNull Call<TokenModel> call, @NonNull Throwable t) {

                }
            });

        }

    }

    @Override
    public void onFailure(Call<T> call, Throwable t) {
        Log.e(TAG, t.toString());
    }

    private void retryMainRequest() {
        Log.i(TAG, "Retry request");
        call.clone().enqueue(this);
    }
}

编辑:我忘记了一些代码:

RetrofitClientInstance.java

public class RetrofitClientInstance {
    private static Retrofit retrofit;
    private static final String BASE_URL = "myurl.com";

    public static Retrofit getRetrofitInstance() {

        OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
        httpClient.addNetworkInterceptor(new AuthInterceptor()); // I added that

            retrofit = new retrofit2.Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .client(httpClient.build())
                    .build();
        return retrofit;
    }
}

AuthInterceptor.java

public class AuthInterceptor implements Interceptor {

    Config config = Config.getInstance();
    @Override
    public Response intercept(Chain chain) throws IOException
    {

        Request request = chain.request();
        request = request.newBuilder()
                .addHeader("X-AUTH-TOKEN", config.token).build();

        return chain.proceed(request);
    }
}