У меня проблема с кинжалом 2. Вкратце, кинжал 2 делает инъекцию в моем фрагменте, и если срок действия токена истек. TokenAuthenticator запрашивает новый токен, который сохраняется в SharedPreferences.
Мой фрагмент не воссоздан, и кинжал 2 использует токен с истекшим сроком для совершения вызова вместо нового.
Теперь я подробно объясню.
Кинжал 2
Логика моего кинжала 2 тривиальна.
NetworkModule.java
@Provides
@Nullable
String provideAuthToken(Context context) {
return AccountUtils.getCurrentUserToken(context);
}
@Provides
AuthenticationInterceptor provideInterceptor(@Nullable String authToken) {
return new AuthenticationInterceptor(authToken);
}
@Provides
TokenAuthenticator provideAuthenticator(Context context, @Nullable String authToken) {
return new TokenAuthenticator(context, authToken);
}
@Provides
OkHttpClient.Builder provideOkHttpClientBuilder(AuthenticationInterceptor interceptor, TokenAuthenticator authenticator) {
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClientBuilder.connectTimeout(15, TimeUnit.SECONDS);
okHttpClientBuilder.readTimeout(15, TimeUnit.SECONDS);
okHttpClientBuilder.writeTimeout(15, TimeUnit.SECONDS);
if (!okHttpClientBuilder.interceptors().contains(interceptor)) {
okHttpClientBuilder.addInterceptor(interceptor);
okHttpClientBuilder.authenticator(authenticator);
}
return okHttpClientBuilder;
}
Он получает токен от SharedPreferences
и выполняет модернизацию для вызова API.
Модифицированный звонок
Затем я делаю простой вызов API (это GET с токеном авторизации)
ProfileFragment.java
@Inject
ViewModelFactory viewModelFactory;
UserViewModel userViewModel;
@Override
public void onAttach(Context context) {
((BaseApplication) context.getApplicationContext())
.getAppComponent()
.inject(this);
super.onAttach(context);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_profile, container, false);
...
userViewModel = ViewModelProviders.of(this, viewModelFactory).get(UserViewModel.class);
userViewModel.getUserInfoMutableLiveData().observe(this, this::consumeResponse);
...
}
private void consumeResponse(UserResponse userResponse) {
switch (userResponse.status) {
case LOADING:
showProgressBar();
break;
case SUCCESS:
handleSuccessResponse(userResponse.data);
break;
case ERROR:
dismissAll();
if (getActivity() != null) {
ResponseHelper.handleErrorResponse(getActivity(), userResponse.error,
mContainer, mMainContainer, this);
}
break;
}
}
Обновить токен
Теперь позвольте мне объяснить, что происходит.
ProfileFragment создан, кинжал 2 использует инъекцию для создания компонентов, сохраняя токен в SharedPreferences
.
ProfileFragment выполняет вызов API, он получает код ошибки 401 из-за истечения срока действия токена.
TokenAuthenticatior вызывается для обновления токена, успешно обновляет токен и сохраняет токен NEW в SharedPreferences
.
Информация о пользователе вызывается снова, однако, поскольку ProfileFragment не воссоздается, он выполняет вызов с тем же внедрением зависимости, которое имеет старый токен. Он вызывает API со старым токеном, затем мы получаем ошибку 401.
Если я сейчас покину эту страницу и вернусь, она будет работать нормально, потому что она снова выполняет внедрение зависимостей и получает новый токен, сохраненный в SharedPreferences
.
Решения
- Вот почему я думал о том, как снова сделать инъекцию. Например, воссоздание фрагмента профиля, но я не думаю, что это хорошая идея. У меня не было проблем с этим перед использованием кинжала 2.
Надеюсь, кто-нибудь поможет. Спасибо!