Retrofit + RxJava no puede almacenar en caché las respuestas, los encabezados de respuesta sospechados
Estoy tratando de configurar caché con Retrofit 1.9.0
y OkHtttp 2.5.0
.
Aquí es cómo OkHttpClient
para mi RestAdapter
:
- ¿Cuál es la forma correcta de manejar suscripciones en RxJava / RxAndroid para un ciclo de vida de actividad?
- RxJava + Retrofit -> BaseObservable para llamadas API para manejo centralizado de respuesta
- Excepción fatal lanzada en el subprograma Scheduler.Worker con Retrofit 2 y Rx
- RxJava- validación de formulario RxAndroid en dynamic EditText
- No se puede eliminar la acción javaCompile antigua, tal vez el nombre de la clase ha cambiado
@Provides @Singleton public OkHttpClient provideOkHttpClient() { OkHttpClient okHttpClient = new OkHttpClient(); okHttpClient.setConnectTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); okHttpClient.setReadTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); okHttpClient.setWriteTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); File cacheDir = new File(context.getCacheDir(), "http"); final Cache cache = new Cache(cacheDir, DISK_CACHE_SIZE_IN_BYTES); okHttpClient.setCache(cache); okHttpClient.interceptors().add(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Response response = chain.proceed(request); Response finalResponse = response.newBuilder() .header("Cache-Control", String.format("public, max-stale=%d", 604800)) .build(); Log.d("OkHttp", finalResponse.toString()); Log.d("OkHttp Headers", finalResponse.headers().toString()); return finalResponse; } }); return okHttpClient; }
No me olvidé de setClient
en RestAdapter.Builder
. También se aseguró de que en realidad estoy usando la instancia de RestAdapter
con este conjunto de clientes.
Incluso comprobado si los archivos se crean en la carpeta "http". Son.
Sin embargo después de que me doy vuelta de WIFI y recargue mi pantalla termino para arriba en OnError
callback del extremo Observable
con este mensaje:
retrofit.RetrofitError: failed to connect to /10.40.31.12 (port 8888) after 10000ms: connect failed: ENETUNREACH (Network is unreachable)
EXENCIÓN DE RESPONSABILIDAD: Debo mencionar que el Observable
final se combina de otros 5, con flatMap
y zip
en el camino.
- ¿Cómo reconstruir o restablecer caché Observable, utilizado con Retrofit para obtener nuevos datos?
- RxJava - cómo invocar abonado en eventos de 4 clics en Android
- RxAndroid textview eventos llamados automáticamente antes de cambios de texto eventos
- Rx 2 Android ¿qué es mejor Single o Observable para llamadas api?
- RxJava Break Chain en Condicional
- Cómo emitir elementos de una lista con retraso en RxJava?
- Android RX - Observable.timer solo disparando una vez
- InterruptedIOException al usar Retrofit2 con rx cuando retryOn
Creo que tengo una respuesta. Un corto es: "No se puede hacer si el servidor envía el encabezado de no-cache en respuesta".
Si desea la más larga, los detalles están a continuación.
He hecho una aplicación de ejemplo comparando 2 backends. Vamos a llamar a Backend A, y Backend B. A me estaba dando problemas, así que he decidido comprobar en B.
A devuelve CacheControl = "no-cache, no-transform, max-age=0"
B devuelve Cache-Control = „public"
encabezado de respuesta Cache-Control = „public"
Hice la misma configuración para ambos backends, sólo diferentes urls.
private void buildApi() { Gson gson = new GsonBuilder().create(); OkHttpClient okHttpClient = new OkHttpClient(); okHttpClient.setConnectTimeout(10, TimeUnit.SECONDS); File cacheDir = new File(getCacheDir(), "http"); final Cache cache = new Cache(cacheDir, 1000000 * 10); okHttpClient.setCache(cache); okHttpClient.interceptors().add(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Log.d("OkHttp REQUEST", request.toString()); Log.d("OkHttp REQUEST Headers", request.headers().toString()); Response response = chain.proceed(request); response = response.newBuilder() .header("Cache-Control", String.format("public, max-age=%d, max-stale=%d", 60, RESPONSE_CACHE_LIFESPAN_IN_SECONDS)) .build(); Log.d("OkHttp RESPONSE", response.toString()); Log.d("OkHttp RESPONSE Headers", response.headers().toString()); return response; } }); RestAdapter.Builder builder = new RestAdapter.Builder() .setConverter(new StringGsonConverter(gson)) .setClient(new OkClient(okHttpClient)) .setRequestInterceptor(new RequestInterceptor() { @Override public void intercept(RequestFacade request) { if (isNetworkAvailable()) { request.addHeader("Cache-Control", "public, max-age=" + 60); } else { request.addHeader("Cache-Control", "public, only-if-cached, max-stale=" + RESPONSE_CACHE_LIFESPAN_IN_SECONDS); } } }); builder.setEndpoint("http://this.is.under.vpn.so.wont.work.anyway/api"); A_API = builder.build().create(AApi.class); builder.setEndpoint("http://collector-prod-server.elasticbeanstalk.com/api"); B_API = builder.build().create(BApi.class); }
Hicimos las dos llamadas, entonces wifi discapacitados. Cache funcionó bien para B, pero A lanzado 504 Unsatisfiable Request (only-if-cached)
Parece que sobrescribir encabezados no ayudará en ese caso.
Deberá volver a escribir su Request
lugar de la Response
. Para referencia, vea los documentos sobre las solicitudes de reescritura . Tenga en cuenta que, también puede utilizar la clase CacheControl
lugar de construir su propia cabecera si lo desea. Su interceptor debe ser algo como –
okHttpClient.interceptors().add(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Request cachedRequest = request.newBuilder() .cacheControl(new CacheControl.Builder() .maxStale(7, TimeUnit.DAYS) .build()) .build(); return chain.proceed(cachedRequest); } });
- Tabs + ViewPager + FragmentStatePagerAdapter – ¿Cómo eliminar el fragmento?
- Android addJavascriptInterface equivalente en iOS