Дооснащение ОХТТП Не работает автономное кеширование - PullRequest
0 голосов
/ 21 октября 2018

Я прочитал десятки уроков и Stackoverflow ответы на мою проблему, но ничего не работает для меня!Кроме того, большинство из них старые, поэтому, вероятно, OKHTTP как-то изменился.

Все, что я хочу, это включить автономное кэширование для модернизации.

Я использую GET

Я пытался использовать только offlineCacheInterceptor в качестве перехватчика, но получал:

Unable to resolve host "jsonplaceholder.typicode.com": No address associated with hostname

Я пытался использовать комбинацию offlineCacheInterceptor в качестве перехватчика + provideCacheInterceptor() в качествеNetworkInterceptor, но я продолжал получать:

504 Unsatisfiable Request (only-if-cached) and a null response.body()

Я даже удостоверился, что добавил .removeHeader("Pragma") везде!


Я попробовал все эти ссылки:

https://newfivefour.com/android-retrofit2-okhttp3-cache-network-request-offline.html (один перехватчик, не работает !!)

https://medium.com/mindorks/caching-with-retrofit-store-responses-offline-71439ed32fda (один перехватчик, не работает!)

https://caster.io/lessons/retrofit-2-offline-cache (отдельный онлайн +Кэширование в автономном режиме, не работает)

https://www.journaldev.com/23297/android-retrofit-okhttp-offline-caching (не работает, 504 неудовлетворительный запрос (только при кэшировании))

http://mikescamell.com/gotcha-when-offline-caching-with-okhttp3/ (один перехватчик, неработает !!)

https://stackoverflow.com/a/48295397/8086424 (не работает) Невозможно разрешить хост "jsonplaceholder.typicode.com": нет адреса, связанного с именем хоста

Можно модифицировать с помощью OKHttpиспользовать CAче данные в оффлайне (СЛИШКОМ сбивает с толку!)


Вот мой код:

public static Retrofit getRetrofitInstance(Context context) {
        if (retrofit == null) {
            c = context;
            int cacheSize = 10 * 1024 * 1024; // 10 MB
            Cache cache = new Cache(context.getCacheDir(), cacheSize);
            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .addInterceptor(provideHttpLoggingInterceptor())
                    .addInterceptor(offlineCacheInterceptor)
                    .addNetworkInterceptor(provideCacheInterceptor())
                    .cache(cache)
                    .build();
            //////////////////////////
            retrofit = new retrofit2.Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(okHttpClient)
                    .build();
        }
        return retrofit;
    }

 public static Interceptor offlineCacheInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Log.e("bbbb", "bbbb");
            if (!checkInternetAvailability()) {
                Log.e("aaaaa", "aaaaaa");
                CacheControl cacheControl = new CacheControl.Builder()
                        .maxStale(30, TimeUnit.DAYS)
                        .build();

                request = request.newBuilder()
                        .cacheControl(cacheControl)
                        .removeHeader("Pragma")
                        .build();
            }
            return chain.proceed(request);
        }
    };

 public static Interceptor provideCacheInterceptor() {
        return new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Response response = chain.proceed(chain.request());

                // re-write response header to force use of cache
                CacheControl cacheControl = new CacheControl.Builder()
                        .maxAge(2, TimeUnit.MINUTES)
                        .build();

                return response.newBuilder()
                        .header(CACHE_CONTROL, cacheControl.toString())
                        .removeHeader("Pragma")
                        .build();
            }
        };
    }

IЯ использую jsonplaceholder.typicode.com/photos, который возвращает:

content-type: application/json; charset=utf-8
    date: Sun, 21 Oct 2018 14:26:41 GMT
    set-cookie: __cfduid=d9e935012d2f789245b1e2599a41e47511540132001; expires=Mon, 21-Oct-19 14:26:41 GMT; path=/; domain=.typicode.com; HttpOnly
    x-powered-by: Express
    vary: Origin, Accept-Encoding
    access-control-allow-credentials: true
    expires: Sun, 21 Oct 2018 18:26:41 GMT
    x-content-type-options: nosniff
    etag: W/"105970-HCYFejK2YCxztz8++2rHnutkPOQ"
    via: 1.1 vegur
    cf-cache-status: REVALIDATED
    expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
    server: cloudflare
    cf-ray: 46d466910cab3d77-MXP
    Cache-Control: public, max-age=60

1 Ответ

0 голосов
/ 23 октября 2018

Октябрь2018 (Retrofit 2.4 или OKHTTP 3.11) Полное решение

Хорошо, поэтому онлайн и автономное кэширование с использованием OKHTTP или Retrofit вызывает много проблем у многих людей на стеке и других форумах.В Интернете существует множество вводящей в заблуждение информации и примеров неработающего кода.

Итак, сегодня я объясню, как можно реализовать онлайн и офлайн кэширование с использованием Retrofit & OKHTTP с четкими шагами + Как тестировать и знатьполучаете ли вы данные из кеша или сети.

Если вы получаете 504 Unsatisfiable Request (only-if-cached) ИЛИ Unable to resolve host "HOST": No address associated with hostname, тогда вы можете использовать любое из следующих решений.

Прежде чем начать, вы всегда должны помнить:

  • Убедитесь, что вы используете запрос GET, а не POST!
  • Всегда убедитесь, что вы добавляете .removeHeader("Pragma"), как показано ниже (это позволяет переопределить протокол кэширования сервера)
  • Избегайте использования HttpLoggingInterceptor во время тестирования, это может вызвать некоторую путаницу в начале.Включите его в конце, если хотите.
  • ВСЕГДА ВСЕГДА удаляйте ваше приложение с устройства и переустанавливайте его снова при каждом изменении кода, если вы хотите исследовать с помощью перехватчиков.В противном случае изменение кода, пока старые данные кэша все еще находятся на устройстве, приведет к путанице и вводящим в заблуждение выводам!
  • Порядок добавления перехватчиков в объект OKHTTPClient имеет значение!

Примечание:Если вы хотите зависеть от протокола кэширования вашего сервера для оперативного и автономного кэширования, не читайте 2 решения.Просто прочитайте эту статью .Все, что вам нужно, это создать объект кеша и прикрепить его к объекту OKHTTPClient.


Решение 1: (длиннее, но у вас есть полный контроль)

  • Шаг 1: (Создать onlineInterceptor)

       static Interceptor onlineInterceptor = new Interceptor() {
        @Override
        public okhttp3.Response intercept(Chain chain) throws IOException {
            okhttp3.Response response = chain.proceed(chain.request());
            int maxAge = 60; // read from cache for 60 seconds even if there is internet connection
            return response.newBuilder()
                    .header("Cache-Control", "public, max-age=" + maxAge)
                    .removeHeader("Pragma")
                    .build();
        }
    };
    
  • Шаг 2: (Создать Offline Interceptor) (Только если вы хотите доступ к кэшу в автономном режиме)

       static Interceptor offlineInterceptor= new Interceptor() {
       @Override
        public okhttp3.Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        if (!isInternetAvailable()) {
            int maxStale = 60 * 60 * 24 * 30; // Offline cache available for 30 days 
            request = request.newBuilder()
                    .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                    .removeHeader("Pragma")
                    .build();
          }
          return chain.proceed(request);
       }
     };
    
  • Шаг 3: (Создать объект кэша)

    int cacheSize = 10 * 1024 * 1024; // 10 MB
    Cache cache = new Cache(context.getCacheDir(), cacheSize);
    
  • Шаг 4: (Добавить перехватчики и кэш в объект OKHTTPClient)

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
     // .addInterceptor(provideHttpLoggingInterceptor()) // For HTTP request & Response data logging
        .addInterceptor(OFFLINE_INTERCEPTOR)
        .addNetworkInterceptor(ONLINE_INTERCEPTOR)
        .cache(cache)
        .build();
    
  • Шаг 5: (Если вы используете Retrofit, добавьте к нему объект OKHTTPClient)

             retrofit = new retrofit2.Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(okHttpClient)
            .build();
    

DONE!


Решение 2: (просто используйте библиотеку, чтобы сделать все это за вас! Но справьтесь с ограничениями)

Используйте OkCacheControl библиотека

  • Шаг 1 (Создать объект Cache, как показано выше)
  • Шаг 2 (Создать объект OKHTTPClient)

         OkHttpClient okHttpClient = OkCacheControl.on(new OkHttpClient.Builder())
         .overrideServerCachePolicy(1, MINUTES)
         .forceCacheWhenOffline(networkMonitor)
         .apply() // return to the OkHttpClient.Builder instance
       //.addInterceptor(provideHttpLoggingInterceptor())
         .cache(cache)
         .build();
    
  • Шаг 3: (Присоедините объект OKHTTPClient to Модификация, как показано выше)

  • Шаг 4: (Создать объект NetworkMonitor)

       static OkCacheControl.NetworkMonitor networkMonitor=new 
       OkCacheControl.NetworkMonitor() {
       @Override
        public boolean isOnline() {
        return isInternetAvailable();
       }
      };
    

DONE!


Тестирование: Чтобы узнать, получает ли ваше устройство данные из сети или из кэша, просто добавьте следующий код в onResponse метод Retrofit.

 public void onResponse(Call<List<RetroPhoto>> call, Response<List<RetroPhoto>> response) {
            if (response.raw().cacheResponse() != null) {
                Log.e("Network", "response came from cache");
            }

            if (response.raw().networkResponse() != null) {
                Log.e("Network", "response came from server");
            }
        }

Если устройство использует сеть, вы получите «ответ с сервера».

Если устройство использует кэш, вы получите оба из приведенных выше ответов!Подробнее об этом читайте в статье .


Подробнее об использовании перехватчиков OKHTTP см. На этой странице .

...