Estoy tratando de usar Retrofit y OKHttp para almacenar en caché las respuestas HTTP. Seguí esta esencia y terminé con este código:
File httpCacheDirectory = new File(context.getCacheDir(), "responses");
HttpResponseCache httpResponseCache = null;
try {
httpResponseCache = new HttpResponseCache(httpCacheDirectory, 10 * 1024 * 1024);
} catch (IOException e) {
Log.e("Retrofit", "Could not create http cache", e);
}
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setResponseCache(httpResponseCache);
api = new RestAdapter.Builder()
.setEndpoint(API_URL)
.setLogLevel(RestAdapter.LogLevel.FULL)
.setClient(new OkClient(okHttpClient))
.build()
.create(MyApi.class);
Y este es MyApi con los encabezados Cache-Control
public interface MyApi {
@Headers("Cache-Control: public, max-age=640000, s-maxage=640000 , max-stale=2419200")
@GET("/api/v1/person/1/")
void requestPerson(
Callback<Person> callback
);
Primero solicito en línea y verifico los archivos de caché. La respuesta correcta JSON y los encabezados están ahí. Pero cuando trato de solicitar fuera de línea, siempre obtengo RetrofitError UnknownHostException
. ¿Hay algo más que deba hacer para que Retrofit lea la respuesta del caché?
EDITAR:
ya que OKHttp 2.0.x HttpResponseCache
es Cache
, setResponseCache
essetCache
Cache-Control: s-maxage=1209600, max-age=1209600
, no sé si es suficiente.public
palabra clave era necesaria para estar en el encabezado de respuesta para que funcione sin conexión. Pero, estos encabezados no permiten que OkClient use la red cuando está disponible. ¿Hay alguna forma de establecer una política / estrategia de caché para usar la red cuando esté disponible?max-stale + max-age
se pasa, se solicita de la red. Pero quiero establecer max-stale a la semana. Esto hace que lea la respuesta del caché incluso si hay una red disponible.Respuestas:
Editar para Retrofit 2.x:
OkHttp Interceptor es la forma correcta de acceder a la memoria caché cuando está desconectado:
1) Crear interceptor:
2) Cliente de configuración:
3) Agregar cliente para actualizar
También puedes ver @kosiara - Bartosz Kosarzycki 's respuesta . Es posible que deba eliminar algún encabezado de la respuesta.
OKHttp 2.0.x (Verifique la respuesta original):
Desde OKHttp 2.0.x
HttpResponseCache
esCache
,setResponseCache
essetCache
. Entonces te deberíasetCache
gustar esto:Respuesta original
Resulta que la respuesta del servidor debe tener
Cache-Control: public
que hacerOkClient
para leer desde el caché.Además, si desea solicitar desde la red cuando esté disponible, debe agregar el
Cache-Control: max-age=0
encabezado de solicitud. Esta respuesta muestra cómo hacerlo parametrizado. Así es como lo usé:fuente
HttpResponseCache has been renamed to Cache.** Install it with OkHttpClient.setCache(...) instead of OkHttpClient.setResponseCache(...)
.if (Utils.isNetworkAvailable(context))
correcta o se supone que se invierte, es decirif (!Utils.isNetworkAvailable(context))
?public okhttp3.Response intercept(Chain chain) throws IOException
nunca se llama, solo se llama cuando estoy en líneaTodas las respuestas anteriores no funcionaron para mí. Traté de implementar caché sin conexión en la actualización 2.0.0-beta2 . Agregué un interceptor usando el
okHttpClient.networkInterceptors()
método, pero recibíjava.net.UnknownHostException
cuando intenté usar el caché sin conexión. Resultó que tenía que agregarokHttpClient.interceptors()
también.El problema era que el caché no se escribió en el almacenamiento flash porque el servidor regresó, lo
Pragma:no-cache
que impide que OkHttp almacene la respuesta. La memoria caché sin conexión no funcionó incluso después de modificar los valores del encabezado de la solicitud. Después de algunas pruebas y errores, conseguí que el caché funcionara sin modificar el lado del backend eliminando pragma de la respuesta en lugar de la solicitud:response.newBuilder().removeHeader("Pragma");
Actualización: 2.0.0-beta2 ; OkHttp: 2.5.0
...
...
fuente
interceptors ()
ynetworkInterceptors ()
son idénticos. ¿Por qué duplicaste esto?.networkInterceptors().add()
yinterceptors().add()
?Mi solución:
fuente
La respuesta es SÍ, según las respuestas anteriores, comencé a escribir pruebas unitarias para verificar todos los casos de uso posibles:
Construí una pequeña biblioteca auxiliar para configurar la memoria caché OKHttp fácilmente, puede ver la prueba de unidad relacionada aquí en Github: https://github.com/ncornette/OkCacheControl/blob/master/okcache-control/src/test/java/com/ ncornette / cache / OkCacheControlTest.java
Unittest que demuestra el uso de caché cuando está desconectado:
Como puede ver, la memoria caché se puede usar incluso si ha caducado. Espero que ayude.
fuente
Basándome en la respuesta de @ kosiara-bartosz-kasarzycki , creé un proyecto de muestra que se carga correctamente desde la memoria-> disco-> red usando retrofit, okhttp, rxjava y guava. https://github.com/digitalbuddha/StoreDemo
fuente
Caché con Retrofit2 y OkHTTP3:
Método estático NetworkUtils.isNetworkAvailable ():
Luego simplemente agregue el cliente al generador de actualizaciones:
Fuente original: https://newfivefour.com/android-retrofit2-okhttp3-cache-network-request-offline.html
fuente