android caching retrofit okhttp

android - Almacenamiento en caché HTTP con Retrofit 2.0.x



caching okhttp (5)

En su CachingControlInterceptor , crea nuevas solicitudes, pero nunca las usa realmente. Llama a newBuilder e ignora el resultado, por lo que la modificación del encabezado nunca se envía a ningún lugar. Intente asignar esos valores a la request y luego, en lugar de llamar a proceed en chain.request() lo request .

public class CachingControlInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); // Add Cache Control only for GET methods if (request.method().equals("GET")) { if (ConnectivityUtil.checkConnectivity(getContext())) { // 1 day request = request.newBuilder() .header("Cache-Control", "only-if-cached") .build(); } else { // 4 weeks stale request = request.newBuilder() .header("Cache-Control", "public, max-stale=2419200") .build(); } } Response originalResponse = chain.proceed(request); return originalResponse.newBuilder() .header("Cache-Control", "max-age=600") .build(); } }

Estoy intentando guardar en caché algunas respuestas en mi aplicación usando Retrofit 2.0, pero me falta algo.

Instalé un archivo de almacenamiento en caché de la siguiente manera:

private static File httpCacheDir; private static Cache cache; try { httpCacheDir = new File(getApplicationContext().getCacheDir(), "http"); httpCacheDir.setReadable(true); long httpCacheSize = 10 * 1024 * 1024; // 10 MiB HttpResponseCache.install(httpCacheDir, httpCacheSize); cache = new Cache(httpCacheDir, httpCacheSize); Log.i("HTTP Caching", "HTTP response cache installation success"); } catch (IOException e) { Log.i("HTTP Caching", "HTTP response cache installation failed:" + e); } public static Cache getCache() { return cache; }

que crea un archivo en /data/user/0/<PackageNmae>/cache/http , luego preparó un interceptor de red de la siguiente manera:

public class CachingControlInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); // Add Cache Control only for GET methods if (request.method().equals("GET")) { if (ConnectivityUtil.checkConnectivity(getContext())) { // 1 day request.newBuilder() .header("Cache-Control", "only-if-cached") .build(); } else { // 4 weeks stale request.newBuilder() .header("Cache-Control", "public, max-stale=2419200") .build(); } } Response originalResponse = chain.proceed(chain.request()); return originalResponse.newBuilder() .header("Cache-Control", "max-age=86400") .build(); } }

mi instancia de Retrofit y OkHttpClient :

OkHttpClient client = new OkHttpClient(); client.setCache(getCache()); client.interceptors().add(new MainInterceptor()); client.interceptors().add(new LoggingInceptor()); client.networkInterceptors().add(new CachingControlInterceptor()); Retrofit restAdapter = new Retrofit.Builder() .client(client) .baseUrl(Constants.BASE_URL) .addConverterFactory(GsonConverterFactory.create(gson)) .build(); productsService = restAdapter.create(ProductsService.class);

donde ProductsService.class contiene:

@Headers("Cache-Control: max-age=86400") @GET("categories/") Call<PagedResponse<Category>> listCategories();

y

Call<PagedResponse<Category>> call = getRestClient().getProductsService().listCategories(); call.enqueue(new GenericCallback<PagedResponse<Category>>() { // whatever // GenericCallback<T> implements Callback<T> } });

La pregunta aquí es: ¿Cómo hacer que tenga acceso a las respuestas en caché cuando el dispositivo está fuera de línea?

El encabezado de la respuesta del servidor es:

Allow → GET, HEAD, OPTIONS Cache-Control → max-age=86400, must-revalidate Connection → keep-alive Content-Encoding → gzip Content-Language → en Content-Type → application/json; charset=utf-8 Date → Thu, 17 Dec 2015 09:42:49 GMT Server → nginx Transfer-Encoding → chunked Vary → Accept-Encoding, Cookie, Accept-Language X-Frame-Options → SAMEORIGIN x-content-type-options → nosniff x-xss-protection → 1; mode=block


OkHttpClient client = new OkHttpClient.Builder().cache(cache).build();


también puedes probar:

public class CachingInterceptor implements Interceptor { @Override public okhttp3.Response intercept(Chain chain) throws IOException { Request request = chain.request(); request = new Request.Builder() .cacheControl(new CacheControl.Builder() .maxAge(1, TimeUnit.DAYS) .minFresh(4, TimeUnit.HOURS) .maxStale(8, TimeUnit.HOURS) .build()) .url(request.url()) .build(); return chain.proceed(request); } }


Finalmente recibo la respuesta.

El interceptor de red debe ser el siguiente:

public class CachingControlInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); // Add Cache Control only for GET methods if (request.method().equals("GET")) { if (ConnectivityUtil.checkConnectivity(YaootaApplication.getContext())) { // 1 day request = request.newBuilder() .header("Cache-Control", "only-if-cached") .build(); } else { // 4 weeks stale request = request.newBuilder() .header("Cache-Control", "public, max-stale=2419200") .build(); } } Response originalResponse = chain.proceed(request); return originalResponse.newBuilder() .header("Cache-Control", "max-age=600") .build(); } }

luego, instalar el archivo de caché es así de simple

long SIZE_OF_CACHE = 10 * 1024 * 1024; // 10 MiB Cache cache = new Cache(new File(context.getCacheDir(), "http"), SIZE_OF_CACHE); OkHttpClient client = new OkHttpClient(); client.cache(cache); client.networkInterceptors().add(new CachingControlInterceptor());


Finalmente descubrí la solución que funcionó para mí en Retrofit 2.x y OkHttp 3.x

Tuve que implementar dos Interceptores , uno de ellos es responsable de reescribir los encabezados de Solicitud y el otro para reescribir los encabezados de Respuesta .

  1. Primero, asegúrese de eliminar cualquier caché anterior. (root explorer /data/data/com.yourapp/cache

  2. Crear una instancia del constructor del cliente:

    OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder() .cache(cache) .addInterceptor(new RewriteRequestInterceptor()) .addNetworkInterceptor(new RewriteResponseCacheControlInterceptor())

  3. Crear RewriteRequestInterceptor

    public class RewriteRequestInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { int maxStale = 60 * 60 * 24 * 5; Request request; if (NetworkUtils.isNetworkAvailable()) { request = chain.request(); } else { request = chain.request().newBuilder().header("Cache-Control", "max-stale=" + maxStale).build(); } return chain.proceed(request); } }

  4. Crear RewriteResponseCacheControlInterceptor

    public class RewriteResponseCacheControlInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { int maxStale = 60 * 60 * 24 * 5; Response originalResponse = chain.proceed(chain.request()); return originalResponse.newBuilder().header("Cache-Control", "public, max-age=120, max-stale=" + maxStale).build(); } }

Es importante asegurarse de agregar el ResponseCacheControlInterceptor como un Interceptor de Red, y el RewriteRequestInterceptor como un Interceptor (como lo hice en el segundo paso).