在 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 集成(令牌)时记住以下事项。
- 我们使用应用程序时令牌可能随时过期
- 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);
}
}
我尝试在我的应用程序中改进改造请求和自定义回调。当我登录时,我的后端会为用户生成一个令牌。每 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 集成(令牌)时记住以下事项。
- 我们使用应用程序时令牌可能随时过期
- 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);
}
}