[Xamarin.Forms] Mejorar el rendimiento al trabajar con imágenes

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.

El ejemplo

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:

Mejoras en la gestión de imágenes en Xamarin.Forms 4.0

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:

La comparativa

NOTA: Los datos salen de la media de 5 medidas.

Puedes encontrar los ejemplos utilizados así como archivos Excel con las medidas en GitHub:

Ver 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

Anuncios

3 pensamientos en “[Xamarin.Forms] Mejorar el rendimiento al trabajar con imágenes

Responder a elbruno Cancelar respuesta

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s