简体   繁体   English

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

[英]Wait for the request in a Retrofit2 Callback in Android Studio

I try to get better with retrofit requests and custom callbacks in my application.我尝试在我的应用程序中改进改造请求和自定义回调。 When I log in, my backend generates a token for the user.当我登录时,我的后端会为用户生成一个令牌。 Every X seconds/minutes , my token becomes deprecated and I need to generate/refresh a new token when I do a new request.X seconds/minutes ,我的令牌就会被弃用,我需要在执行新请求时生成/刷新新令牌。

The problem I have is that when the token is deprecated, I can't generate a new one before the request.我遇到的问题是,当令牌被弃用时,我无法在请求之前生成一个新的。

In MainActivity.javaMainActivity.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);
                }
            });

In MyCallback.javaMyCallback.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());
   }
}

It seems like I do the main request before (or during) the refresh token request.似乎我在刷新令牌请求之前(或期间)执行了主要请求。

How can I improve my code to do this step by step (refresh the token then do the main request)?如何改进我的代码以逐步执行此操作(刷新令牌然后执行主要请求)?

Thanks for your help.谢谢你的帮助。

We have remember below things when using dynamic header integration (tokens).在使用动态标头集成(令牌)时,我们记住了以下内容。

  1. Token may be expiry at any time when we using app我们使用应用程序时,令牌可能随时到期
  2. Error 401 in api's. api 中的错误 401。

so we need the callback for detect token expired when calling api, so we use Authendicator , It's will trigger when our api getting 401(add authenticator class if you have send token with api).所以我们在调用api时需要检测token过期的回调,所以我们使用Authendicator ,当我们的api得到401时它会触发(如果你Authendicator api发送令牌,请添加authenticator类)。

If you getting 401, call your refresh api and then again recall your existing api with new token.如果您收到 401,请调用您的刷新 api,然后再次使用新令牌调用您现有的 api。

Authendicator:验证者:

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

Then add Authendicator to your okhttp client然后将 Authendicator 添加到您的 okhttp 客户端

 .authenticator(new TokenAuthenticator())

So i have found a custom solution that works.所以我找到了一个有效的自定义解决方案。 I hope I will help people with that.我希望我能帮助人们解决这个问题。 I wanted to simplify as much as I can the requests, so this is how looks an http request :我想尽可能地简化请求,所以这是一个 http 请求的样子:

MainActivity.java主活动.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 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);
    }
}

EDIT : I forget some code :编辑:我忘记了一些代码:

RetrofitClientInstance.java改造客户端实例.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 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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM