Introducción
El uso de imágenes en aplicaciones móviles es habitual. Es un elemento clave a la hora de conseguir buenos resultados visuales. Sin embargo, también suelen ser uno de los puntos clave que impactan en el rendimiento de la aplicación. Problemas como:
- Alto consumo de memoria.
- Bloqueo de la UI (carga de imágenes en el hilo de UI, etc).
- Etc.
En este artículo, vamos a realizar comparaciones en el rendimiento del control Image de Xamarin.Forms entre diferentes versiones, así como una comparativa con FFImageLoading y GlideX.
Para realizar las comaparativas vamos a necesitar un ejemplo y algo de código para obtener información. Nuestro ejemplo va a ser una versión modificada del gran ejemplo realizado por Jonathan Peppers en Glidex.
A la hora de medir, vamos a utilizar:
System.Diagnostics.Process.GetCurrentProcess().WorkingSet64
Para obtener la cantidad de bytes que se estan consumiendo.
Imágenes en Xamarin.Forms
El control Image de Xamarin.Forms permite la carga de imágenes desde diferentes fuentes (URL, recurso incrustrado, etc.). El rendimiento general es correcto aunque con mejoras (mejoras en la cache, reutilizar recursos, etc.).
Desde la versión 4.0 de Xamarin.Forms se han comenzado a realizar mejoras en la gestión de imágenes. Pero…¿realmente tenemos mejora?.
Para contestar de forma correcta, vamos a cargar 100 imágenes en un Grid (evitamos usar listados y reutilización de celdas para conseguir tener un volumen elevado de imágenes en el árbol visual y en memoria).
Lanzamos la aplicación tanto utilizando la versión 3.6 como la versión 4.0. Tras lanzar la aplicación 5 veces y hacer la media de la memoria consumida:
Xamarin.Forms 4.0 consume una media de un 15% menos de memoria con respecto a la versión 3.6. Una buena mejora en la gestión de imágenes pero…¿podemos conseguir mejorar más al gestionar las imágenes?.
FFImageLoading
FFImageLoading es una de las librerías de la comunidad más usadas y más recomendadas. Esta librería tiene como objetivo cargar imágenes de la forma más eficiente posible. Entre las características principales (y que tienen impacto en el rendimiento):
- Cache de imágenes en memoria y disco.
- Múltiples imágenes usando el mismo origen (url, ruta, recurso) usarán solo un mapa de bits que se almacena en caché en memoria (menos uso de memoria).
- Placeholders de carga y error.
- Las imágenes se pueden ajustar automáticamente a un tamaño especificado (menos uso de memoria).
- Etc.
Tras realizar benchmarking entre FFImageLoading y el control Image de Xamarin.Forms, gracias a las opciones de cache, ajuste de tamaño, etc., obtenemos mejor rendimiento con FFImageLoading.
GlideX
GlideX.Forms nos permite utilizar Glide (Una librería de carga y almacenamiento de imágenes para Android enfocada en el rendimiento) en Xamarin.Forms Android.
Al igual que anteriormente, hemos realizado benchmarking en Android entre el control Image de Xamarin.Forms, FFImageLoading y GlideX. GlideX es la opción más óptima en Android superando levemente a FFImageLoading y con una diferencia más considerable con respecto al control Image.
IImageSourceHandler
Así que, GlideX es más eficiente en Android pero…¿que usamos en iOS?. Podríamos utilizar FFImageLoading directamente en ambas plataformas, es una buena opción. Sin embargo, podríamos usar FFImageLoading en iOS y GlideX en Android.
Desde Xamarin.Forms 2.3.5, tenemos la interfaz IImageSourceHandler. Permite implementar ImageSource en la plataforma.
Ejemplo básico (en iOS):
public class ImageSourceHandler : IImageSourceHandler { public Task<UIImage> LoadImageAsync( ImageSource imageSource, CancellationToken cancellationToken = new CancellationToken(), float scale = 1) { ... } }
Podemos gestionar la fuente de imágenes de forma sencilla, utilizando en cada plataforma la opción que necesitemos. Jean-Marie Alfonsi ha creado Xamarin.Forms.ImageSourceHandlers con esta misma idea. Su uso es sencillo.
En Android, vamos a utilizar GlideX. Necesitaremos la inicialización de la librería.
Android.Glide.Forms.Init();
Mientras que en iOS, vamos a usar FFImageLoading:
FFImageLoading.FormsHandler.Init();
Benchmarking
Llegados a este punto, tenemos todo lo necesario para obtener datos y sacar algunas conclusiones. La gestión de imágenes es un punto importante a la hora de crear aplicaciones móviles. En Xamarin.Forms se continua mejorando y lo podemos ver en los datos obtenidos comparando la versión 3.6 y la versión 4.0.
A continuación, una comparativa en Android de la misma aplicación cargando 100 imágenes utilizando el control Image de Xamarin.Forms, FFImageLoading y GlideX:
NOTA: Los datos salen de la media de 5 medidas.
Puedes encontrar los ejemplos utilizados así como archivos Excel con las medidas en GitHub:
Otras recomendaciones
Podemos aplicar otra serie de acciones para mejorar considerablemente el rendimiento a la hora de trabajar con imágenes:
- Evitar la necesidad de reducir el tamaño de imágenes (memoria consumida) en el dispositivo. Si tenemos control sobre el servidor proveedor de las imágenes, gestionar las imágenes en el mismo.
- Además del punto anterior, reducir las imágenes locales utilizadas. Podemos conseguirlo de varias formas. Controlando el tamaño (o formato) de la imagen, o bien, se pueden utilizar servicios como tinypng.
Más información
- GitHub: Xamarin.Forms Performance Playground
- Blog de Jean-Marie Alfonsi: Ultimate Image Caching for Xamarin.Forms
- GitHub: FFImageLoading
- GitHub: GlideX