Gestionando la descarga de imágenes en Android (con Glide?)

 

Universal Image Loader, Picasso, Glide, Fresco…..

Cuándo un desarrollador de Android se tropieza por primera vez con las problemáticas habituales que representa la gestión de imágenes (descarga, thumbnails, cache, etc), la existencia de múltiples alternativas perfectamente válidas para solucionar dichos problemas, puede generar verdaderos dolores de cabeza.

De hecho, uno de los primeros pasos que, llegado el momento, muchos hacemos, es buscar una comparativa entre las alternativas más habituales (listadas arriba).

Con soporte para la edición? Con soporte para GIFs? Que esté bien documentada? Con gestión de la cache?  Cómo habitualmente, lo primero será definir nuestros requisitos. Luego solo nos quedará recurrir a una de las múltiples comparativas que podemos encontrar en la red y decidir: cuáles satisfacen nuestros requisitos?

Además de recurrir a una comparativa del estilo, personalmente también recomiendo revisar las respectivas documentaciones, pues estas librerías están en constante cambio y las funcionalidades pueden verse modificadas o extendidas en cualquier momento.

 Si tienes mucha suerte, después de investigar sobre el estado del arte en este ámbito, tendrás una opción única sobre la mesa et voilà! Sin embargo, esto es poco probable que te ocurra (a menos que tengas requisitos muy específicos) y tocará recurrir a tu criterio como desarrollador para tomar una decisión (lo más acertada posible).

YENDO UN PASO MÁS ALLÁ

Uno de los primeros pasos a realizar cuándo queremos indagar en el funcionamiento de una de las alternativas que tenemos sobre la mesa es realizar una pequeña prueba de concepto y empezar a jugar. Hasta aquí todo suele ir bien. Por desgracia, los sistemas son complejos (y más que lo serán), y cuándo somos capaces de que las cosas funcionen para las casuísticas ideales (happy path), nos toca hacer frente a situaciones más complejas.

Sí amigos, una de estas situaciones complejas está relacionada con la conexión, que siempre nos abandona cuándo más la necesitamos, y sobretodo cuándo estamos conectados mediante una red móvil.

Aquí es dónde toca investigar aún un poco más, hacer pruebas y ver qué librería nos facilita más las cosas

Y AHORA QUÉ?

Cuándo algo no funciona, lo primero que debemos hacer es detectar el error y entender porqué no ha funcionado. Sin embargo, esto no siempre es fácil. Veamos un ejemplo de ello con una de las librerías más populares (Picasso):

Un par de callbacks, e ya. Trivial, no?
Y si os digo que cuándo perdemos la conexión a mitad de la descarga de la imagen, el fallback no es llamado? Je, je, je…

Si vamos un poco más allá, descubriremos que en este caso, lo que hace la librería Picasso es descodificar los datos que nos llegan mediante el stream de conexión y los almacena en un Bitmap. Sin embargo, si el stream se cierra antes de hora, la librería no lanzará ningún error y simplemente nos devolverá un Bitmap incompleto.

En estos casos, lo habitual es pensar en la solución más sencilla (guiño a la Navaja de Ockham). Pero no, amigos, en este caso concreto, por ejemplo, no servirá con volver a cargar la imagen: bienvenidos al maravilloso mundo de la cache 😉

Por suerte, como Picasso es una buena librería, tiene implementada una cache a nivel de URI, por lo que nos bastaría con hacer un cache flush del identificador con el que estamos trabajando.

La cuestión es: ¿cuándo debemos hacerlo? ¿debemos poner un botón de refresco para que el usuario pueda recargar las imágenes siempre que quiera? ¿no hacemos uso de la cache? Cómo vimos anteriormente, con Picasso, por ejemplo, no tenemos una forma sencilla de detectar esos casos en los que nuestra imagen no fue descargada de forma correcta (aquí tenéis un issue en el repositorio aún pendiente de ser resuelto, por si queréis darle seguimiento). Por desgracia, a veces no nos quedará más remedio que modificar ligeramente nuestra aplicación para poder hacer frente a estos casos (desactivar la cache, añadir un botón de refresco, etc).

Lo primero que se nos puede pasar por la cabeza es “vale, pues descartamos esta librería”. Pero, ¿es cualquiera de las alternativas válida para dicho propósito? Recordemos que Picasso, a pesar de ser una de las más usadas, no tiene esta problemática resuelta. En este caso, la librería Universal Image Loader (UIL) tampoco tiene resuelta (del todo) esta problemática, pues su implementación también hace uso del “maldito” BitmapFactory.decodeStream.

Por suerte, y aunque no de forma sencilla, en este caso si que podremos detectar que ha habido un error, pues la librería UIL es capaz de detectar cuándo un stream tiene un cierre inesperado. Sin embargo, esto solo será posible en el proceso de gestión de la cache y, por lo tanto, solo será posible cuándo ésta esté activada (obligándonos a ello incluso cuándo no queremos). Como vemos, se trata de un tema cuándo menos complejo.

GLIDE FTW 😀

Si seguimos probando con las alternativas restantes que teníamos sobre la mesa, descubriremos que Glide no hace uso del método decodeStream (al fin!). Por lo tanto, ni gestión de Bitmaps incompletos, ni gestión de excepciones fuera de contexto (en el proceso de gestión de la cache).

Glide, en su caso, tiene una clase DecodeJob responsable de gestionar este proceso de descodificación. De forma similar al ejemplo en Picasso que vimos anteriormente, a esta clase también podremos vincularle varios listeners para la detección y gestión de errores, con la diferencia de que en este caso, Glide si que será capaz de lanzar una excepción de “unexpected end of stream” en el proceso de descodificación y hacer reaccionar al listener apropiado para dicha gestión.

 

Y no, rotundamente no. Éste no se trata de un artículo para promocionar la librería Glide, sino para concienciar a los desarrolladores de que a veces, aunque tengamos muchas alternativas que satisfacen nuestros requisitos puramente funcionales, hay aspectos cómo la facilidad presente en la gestión de los edge cases que pueden ser motivos más que suficientes para que nos decantemos por una u otra opción. Y es en este momento cuándo debemos usar la cabeza, tener criterio y actuar en consecuencia. Ahora bien, puede que haya otras problemáticas que Picasso resuelva mejor que Glide, evidentemente. Lo que está claro es que no es el caso de la pérdida de conexión a media descarga 😉