[Xamarin.Forms] Mejorar el rendimiento en el tiempo de arranque

Introducción

Además de cuidar detalles como la funcionalidad o la apariencia visual de nuestra aplicación, nuestra aplicación debe funcionar correctamente bajo todas las condiciones en todos los dispositivos para la que sea lanzada.

Un punto importante a revisar siempre suele ser, el tiempo de arranque de la aplicación.

¿Conoces conceptos como AOT?, ¿fast renderers?. En este artículo vamos a repasar algunos conceptos que podemos aplicar para tener un impacto positivo en los tiempos de arranque de la aplicación.

XAMLC

Si defines la interfaz de usuario de la aplicación Xamarin.Forms con XAML tienes la opción de utilizar XamlCompilationOptions.

Cuenta con dos valores:

Compile.

  • Acelera la carga de elementos visuales.
  • Reduce el tamaño del paquete.
  • La compilación (AOT) es más larga.

Skip.

  • Valor por defecto para mantener retocompatibilidad con versiones antiguas de Xamarin.Forms.
  • No hay validación en tiempo de ejecución de XAML.

Ejemplo de uso:

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]

La diferencia:

Rendimiento con XAMLC

NOTA: Resultado obtenido tras 5 mediciones utilizando Android.

Fast Renderers

Hablamos de cambios realizados en Xamarin.Forms con el objetivo de reducir a mínimos el número de operaciones y cálculos a realizar para renderizar el control y gestionar su tamaño y posición.

Hasta ahora, la mayoría de los renderers en Android se componían de dos vistas:

  • Control nativo, como Button.
  • Un contenedor ViewGroup que se encargaba de controlar aspectos como los gestos, etc.

Sin embargo, este enfoque tiene una implicación directa en el rendimiento al crear dos elementos por cada control, lo que resulta en un árbol visual más complejo, requiere más memoria y más capacidad de procesamiento para representar en la pantalla.

Los Fast Renderers reducen la inflación y los tiempos para el renderizado de un control de Xamarin.Forms.

Veamos un ejemplo de jerarquía de elementos sin utilizar Fast Renderers:

Jerarquía sin utilizar Fast Renderers

Y utilizando Fast Renderers:

Jerarquía utilizando Fast Renderers

La diferencia:

Rendimiento con Fast Renderers

Los Fast Renderers están disponibles para los siguientes controles de Xamarin.Forms en Android:

  • Button
  • Image
  • Label
  • Frame

Desde Xamarin.Forms 4.0 se utilizan por defecto los Fast Renderers. Si quieres no utilizarlos, puedes hacerlo:

Forms.SetFlags("UseLegacyRenderers");

Configuración de la App

La opción compilación AOT habilita la compilación Ahead Of Time de los ensamblados. Cuando esta opción está habilitada, la sobrecarga de inicio Just-In-Time (JIT) se minimiza al precompilar ensamblados antes del tiempo de ejecución. El código nativo resultante se incluye en el paquete (APK) junto con los ensamblados sin compilar. Esto da como resultado un tiempo de inicio de la aplicación más reducido, pero a costa de tamaños APK más grandes.

A costa de tiempos de compilación más lentos, el compilador de optimización de LLVM debe crear un código compilado más pequeño y rápido (en las pruebas, efectivamente conseguimos un paquete más ligero aunque no tenemos reducción en lso tiempos de arranque de la aplicación).

A continuación, una comparativa del tiempo de arranque de la aplicación en milisegundos entre el uso de JIT, AOT y AOT junto con la opciónde optimización de LLVM:

Rendimiento con diferentes configuraciones

Como se puede observar, la reducción de tiempo usando AOT es notoria pero…¿cómo afecta al tamaño del paquete?.

Comparativa del peso del paquete

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

Ver GitHub

Más información

[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