Cómo evitar las descargas no optimizadas

Algunos de los usuarios de tu app tienen acceso intermitente a Internet o tienen límites en la cantidad de información que pueden descargar en sus dispositivos. Puedes alentar a los usuarios a interactuar con tu app con más frecuencia reduciendo la cantidad de datos que tu app necesita descargar.

La forma más básica de reducir las descargas es descargar solo lo que necesitas. En términos de datos, esto significa implementar APIs de REST que te permitan especificar criterios de consulta que limiten los datos devueltos con parámetros como la hora de la última actualización.

Del mismo modo, cuando se descargan imágenes, se recomienda reducir su tamaño en el servidor, en lugar de descargar imágenes de tamaño completo que se reducen en el cliente.

Almacena en caché las respuestas HTTP

Otra técnica importante es evitar la descarga de datos duplicados. Puedes reducir la probabilidad de descargar los mismos datos de forma repetida con el almacenamiento en caché. Cuando almacenas en caché los datos y recursos de tu app, creas una copia local de la información a la que debe hacer referencia tu app. Si tu app necesita acceder a la misma información varias veces en un período breve, debes descargarla en la caché solo una vez.

Es importante almacenar en caché de la forma más agresiva posible para reducir la cantidad total de datos que descargas. Siempre almacena en caché los recursos estáticos, incluidas las descargas a pedido, como las imágenes de tamaño completo, durante el mayor tiempo posible. Los recursos on-demand deben almacenarse por separado para que puedas vaciar con regularidad la caché on-demand y administrar su tamaño.

Para asegurarte de que el almacenamiento en caché no provoque que tu app muestre datos obsoletos, usa los códigos de estado y encabezados HTTP adecuados, como los encabezados ETag y Last-Modified. Esto te permite determinar cuándo se debe actualizar el contenido asociado. Por ejemplo:

Kotlin

// url represents the website containing the content to place into the cache.
val conn: HttpsURLConnection = url.openConnection() as HttpsURLConnection
val currentTime: Long = System.currentTimeMillis()
val lastModified: Long = conn.getHeaderFieldDate("Last-Modified", currentTime)

// lastUpdateTime represents when the cache was last updated.
if (lastModified < lastUpdateTime) {
    // Skip update
} else {
    // Parse update
    lastUpdateTime = lastModified
}

Java

// url represents the website containing the content to place into the cache.
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
long currentTime = System.currentTimeMillis();
long lastModified = conn.getHeaderFieldDate("Last-Modified", currentTime);

// lastUpdateTime represents when the cache was last updated.
if (lastModified < lastUpdateTime) {
    // Skip update
} else {
    // Parse update
    lastUpdateTime = lastModified;
}

Puedes configurar algunas bibliotecas de redes para que respeten estos códigos de estado y encabezados automáticamente. Cuando usas OkHttp, por ejemplo, configurar un directorio y un tamaño de caché para el cliente permitirá que la biblioteca use el almacenamiento en caché de HTTP, como se muestra en la siguiente muestra de código:

Kotlin

val cacheDir = Context.getCacheDir()
val cacheSize = 10L * 1024L * 1024L // 10 MiB
val client: OkHttpClient = OkHttpClient.Builder()
    .cache(Cache(cacheDir, cacheSize))
    .build()

Java

File cacheDir = Context.getCacheDir();
long cacheSize = 10L * 1024L * 1024L; // 10 MiB
OkHttpClient client = new OkHttpClient.Builder()
    .cache(new Cache(cacheDir, cacheSize))
    .build();

Con la caché configurada, puedes entregar solicitudes HTTP almacenadas por completo en caché directamente desde el almacenamiento local, lo que elimina la necesidad de abrir una conexión de red. Las respuestas almacenadas en caché de forma condicional pueden validar su actualización desde el servidor, lo que elimina el costo de ancho de banda asociado con la descarga. Las respuestas no almacenadas en caché se guardan en la caché de respuestas para solicitudes futuras.

Puedes almacenar en caché datos no sensibles en el directorio de caché externo no administrado con Context.getExternalCacheDir(). Como alternativa, puedes almacenar datos en caché en la caché de la aplicación administrada y segura con Context.getCacheDir(). Ten en cuenta que esta caché interna se puede vaciar cuando el sistema se está quedando sin almacenamiento disponible.

Usar un repositorio

Para obtener un enfoque más sofisticado del almacenamiento en caché, considera el patrón de diseño del repositorio. Esto implica crear una clase personalizada, conocida como repositorio, que proporciona una abstracción de la API sobre algunos datos o recursos específicos. Es posible que, en un principio, el repositorio recupere sus datos de varias fuentes, como un servicio web remoto, pero proporcione a los emisores una versión almacenada en caché de los datos en las llamadas posteriores. Esta capa de direccionamiento indirecto te permite proporcionar una estrategia de almacenamiento en caché sólida que sea específica para tu app. Para obtener más información sobre cómo usar el patrón de repositorio en tu app, consulta la Guía de arquitectura de apps.