Trabajar con imágenes puede generar problemas de rendimiento con rapidez si no tienes cuidado. Incluso un gráfico pequeño en un formato comprimido, como JPG o PNG, puede convertirse en un mapa de bits grande cuando se decodifica para mostrarse.Si no eres eficiente con el uso de gráficos, puedes tener problemas de memoria que afecten el rendimiento de tu app y de otras apps en el dispositivo. Sigue estas prácticas recomendadas para asegurarte de que tu app tenga el mejor rendimiento.
Usa bibliotecas de carga de imágenes
Puedes mejorar la eficiencia de tu app usando bibliotecas de carga de imágenes, como Coil (para proyectos que priorizan Kotlin) o Glide (para proyectos de Java). Estas bibliotecas reducen el uso de memoria de tu app, ya que realizan acciones como almacenar en caché las imágenes, cambiar el tamaño de los gráficos cuando es necesario y reciclar los objetos gráficos.
Cambia el tamaño de las imágenes cuando sea apropiado
Asegúrate de usar el tamaño de la imagen adecuado para tus necesidades. Por ejemplo, nunca debes cargar una imagen grande en una miniatura pequeña. En su lugar, usa un método como inSampleSize para cargar una versión remuestreada de la imagen.
Las bibliotecas de carga de imágenes, como Coil y Glide, controlan este remuestreo automáticamente de forma predeterminada. Puedes configurar sus estrategias de reducción de muestras con ImageLoader (para Coil) o DownsampleStrategy (para Glide).
Proporciona recursos alternativos para diferentes tamaños de pantalla
Si envías imágenes con tu app, considera proporcionar elementos de diferentes tamaños para diferentes resoluciones de dispositivo. Esto puede ayudar a reducir el tamaño de descarga de la app en dispositivos y mejorar el rendimiento, ya que cargará una imagen de menor resolución en un dispositivo de menor resolución. Para obtener más información sobre cómo proporcionar mapas de bits alternativos para diferentes tamaños de dispositivos, consulta la documentación de mapas de bits alternativos.
No apliques relleno directamente
A veces, es posible que debas agregar padding a una imagen. Por ejemplo, es posible que desees que la imagen esté rodeada por un borde transparente para el letterboxing.
En esas situaciones, no agregues el padding directamente a la imagen, ya que esto cambiaría sus dimensiones. En cambio, deja las dimensiones de la imagen como están y ajusta su ubicación en la pantalla con InsetDrawable.
También puedes agregar padding al elemento componible o a la vista que contiene la imagen.
Elige el formato de píxel adecuado
Elige el formato de píxel adecuado para equilibrar la memoria y la calidad. Usa RGB_565 cuando no necesites transparencia. Este formato usa la mitad de la memoria del formato ARGB_8888 predeterminado.
En Glide, puedes configurar esto con DecodeFormat. En Coil, puedes usar la propiedad bitmapConfig.
Usa vectores cuando sea posible
En el caso de las imágenes compuestas por formas geométricas, un gráfico vectorial es mucho más pequeño que un mapa de bits y se ajusta sin problemas a cualquier densidad de pantalla. Cuando sea adecuado, usa elementos como ShapeDrawable para representar gráficos.
Libera y reutiliza mapas de bits cuando puedas
Los archivos gráficos grandes pueden ocupar mucha memoria. Para reducir su impacto, debes liberar o reutilizar los objetos gráficos siempre que puedas.
Si usas una biblioteca de carga de imágenes, asegúrate de liberar los mapas de bits en el grupo administrado de la biblioteca cuando ya no los necesites. La biblioteca puede reutilizar los objetos cuando sea necesario y mantiene un búfer de memoria disponible para necesidades futuras.
Si administras gráficos de forma manual, debes liberar los mapas de bits cuando termines de usarlos llamando a Bitmap.recycle y descartando de inmediato la referencia Bitmap, en lugar de depender de la recolección de elementos no utilizados.
Otras sugerencias y trucos
En esta sección, se enumeran algunas otras formas de mejorar el rendimiento de tu app cuando se controlan gráficos.
No empaquetes imágenes grandes con el archivo AAB o APK
Una de las principales causas del tamaño grande de descarga de apps se debe a los gráficos que se empaquetan dentro del archivo AAB o APK. Usa la herramienta Analizador de APK para asegurarte de no empaquetar archivos de imagen más grandes de lo necesario. Reduce los tamaños o considera colocar las imágenes en un servidor y descargarlas solo cuando sea necesario.
Cómo encontrar mapas de bits redundantes
Si tienes varias copias de la misma imagen, se desperdicia memoria. Puedes usar el generador de perfiles de Android Studio para identificar gráficos redundantes. Usa el analizador de volcado de montón para capturar un volcado de montón y filtra los resultados eligiendo el parámetro de configuración mapas de bits duplicados.
Cuando uses ImageBitmap, llama a prepareToDraw antes de dibujar
Cuando uses ImageBitmap, para comenzar el proceso de carga de textura en la GPU, llama a ImageBitmap#prepareToDraw() antes de dibujarla. Esto ayuda a la GPU a preparar la textura y mejorar el rendimiento de mostrar una imagen en la pantalla. La mayoría de las bibliotecas de carga de imágenes ya realizan esta optimización, pero, si trabajas con la clase ImageBitmap, es una cuestión que debes tener en cuenta.
Opta por pasar un Int DrawableRes o una URL como parámetros a tu elemento componible en lugar de Painter
Debido a las complejidades de lidiar con imágenes (por ejemplo, escribir una función equals para Bitmaps sería costoso desde el punto de vista del procesamiento), la API de Painter no está explícitamente marcada como estable con la anotación @Stable. Las clases inestables pueden generar recomposiciones innecesarias porque el compilador no puede deducir con facilidad si los datos cambiaron.
Por lo tanto, recomendamos pasar una URL o un ID de recurso de elementos de diseño como parámetros al elemento componible, en lugar de pasar Painter como parámetro.
// Prefer this:
@Composable
fun MyImage(url: String) {
}
// Over this:
@Composable
fun MyImage(painter: Painter) {
}
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- ImageBitmap frente a ImageVector {:#bitmap-vs-vector}
- Cómo guardar el estado de la IU en Compose
- Fases de Jetpack Compose