, Для меня фокус заключался в использовании обоих этих перехватчиков. Надеюсь, это поможет вам.
прочитал много вопросов и ответов по моей проблеме, но я не могу понять, как ее решить.
Мне нужно получить ответ от сервера и сохранить его в кеше. После этого, когда устройство находится в автономном режиме, я хочу использовать кэшированный ответ. Когда устройство подключено к сети, я хочу получить ответ именно с сервера.
Выглядит не так сложно.
Вот способ (примеры кода) я пытаюсь сделать это:
1) Способ создания кеша
Cache provideOkHttpCache() {
int cacheSize = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(this.getCacheDir(), cacheSize);
return cache;
}
2) Создать перехватчик для изменения заголовков управления кэшем
Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
CacheControl.Builder cacheBuilder = new CacheControl.Builder();
cacheBuilder.maxAge(0, TimeUnit.SECONDS);
cacheBuilder.maxStale(365, TimeUnit.DAYS);
CacheControl cacheControl = cacheBuilder.build();
Request request = chain.request();
if (isOnline()) {
request = request.newBuilder()
.cacheControl(cacheControl)
.build();
}
okhttp3.Response originalResponse = chain.proceed(request);
if (isOnline()) {
int maxAge = 20; // read from cache
okhttp3.Response response = originalResponse.newBuilder()
.header("cache-control", "public, max-age=" + maxAge)
.build();
return response;
} else {
int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
okhttp3.Response response = originalResponse.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.build();
return response;
}
}
};
3) Создать OkHttpClient и модифицировать
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(httpLoggingInterceptor)
.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
.cache(provideOkHttpCache())
.build();
retrofit = new Retrofit.Builder()
.client(okHttpClient)
.baseUrl("https://randomuser.me/")
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
4) Способ совершить сетевой вызов
private void networkCall() {
Log.v(TAG, "networkCall() is called");
Call<RandomUsers> randomUsersCall = getRandomUserService().getRandomUsers(10);
randomUsersCall.enqueue(new Callback<RandomUsers>() {
@Override
public void onResponse(Call<RandomUsers> call, @NonNull Response<RandomUsers> response) {
if (response.isSuccessful()) {
try {
Log.v(TAG, "headers = " + response.headers());
} catch (Exception e) {
e.printStackTrace();
}
mAdapter = new RandomUserAdapter();
mAdapter.setItems(response.body().getResults());
recyclerView.setAdapter(mAdapter);
} else if (response.code() == 504) {
Log.v(TAG, "response body = " + response.raw().cacheResponse());
}
}
@Override
public void onFailure(Call<RandomUsers> call, Throwable t) {
Log.v("cache-control", "response failure");
}
});
}
Итак, вот в чем проблема: приложение никогда не переходит в автономный блок кода в п.2. Если максимальный возраст все еще разрешен, используйте модифицированный ответ. Если ответ был кэширован некоторое время назад, а максимальный возраст недопустим, есть два случая:
1) Устройство подключено к сети:Retrofit
сделать новый запрос к серверу (все ок)
2) Устройство находится в автономном режиме: метод обратного вызоваonFailure
внутриnetworkCall()
называется (стр.4 примеров кода)
Что не так в моем коде? Я действительно не понимаю, почему приложение не может использовать автономный случай контроля кэша.
Извините за слишком много текста. Спасибо!