优化位图图像

如果不小心,使用图片时可能会快速引入性能问题。即使是采用 JPG 或 PNG 等压缩格式的小型图形,在解码以供显示时也可能会变成大型位图。如果您在图形使用方面不够高效,可能会遇到内存问题,从而影响应用和设备上其他应用的性能。 遵循以下最佳实践可以确保您的应用达到最佳性能。

使用图像加载库

您可以使用图片加载库(例如 Coil [适用于以 Kotlin 为主的项目] 或 Glide [适用于 Java 项目])来提高应用的效率。这些库通过缓存图片、在需要时调整图形大小以及回收图形对象等方式来减少应用的内存用量。

在适当的时候调整图片大小

请务必根据需要使用适当的图片大小。例如,您绝不应将大图片加载到小缩略图中。而应使用 inSampleSize 等方法加载图片的重采样版本。

默认情况下,Coil 和 Glide 等图片加载库会自动为您处理此重采样。您可以使用 ImageLoader(对于 Coil)或 DownsampleStrategy(对于 Glide)配置其降采样策略。

针对不同屏幕尺寸提供备用资源

如果您要在应用中提供图片,请考虑为不同的设备分辨率提供不同大小的资源。这有助于缩减应用在设备端的下载大小,并提高性能,因为这会在分辨率较低的设备上加载分辨率较低的图片。如需详细了解如何针对不同设备尺寸提供备用位图,请查看备用位图文档

请勿直接应用内边距

有时,您可能需要向图片添加内边距。例如,您可能希望在图片周围添加透明边框,以实现信箱模式。在这些情况下,请勿直接向图片添加内边距,以免更改图片的尺寸。相反,请保持图片的尺寸不变,并使用 InsetDrawable 调整图片在屏幕上的位置。或者,您也可以向包含图片的可组合项或视图添加内边距。

选择合适的像素格式

选择合适的像素格式,在内存和质量之间取得平衡。如果不需要透明度,请使用 RGB_565;此格式使用的内存是默认 ARGB_8888 格式的一半。

在 Glide 中,您可以使用 DecodeFormat 配置此项。在 Coil 中,您可以使用 bitmapConfig 属性。

尽可能使用矢量

对于由几何形状组成的图片,矢量图形比位图小得多,并且可以针对任何显示密度平滑缩放。在合适的情况下,使用 ShapeDrawable 等元素来表示图形。

在可以的情况下释放并重复使用位图

大型图形文件可能会占用大量内存。为了减少其影响,您应尽可能释放或重复使用图形对象。

如果您使用图片加载库,请确保在不再需要位图时将其释放到库的受管理池中。该库可以在需要时重复使用这些对象,并保留内存缓冲区以供将来使用。

如果您是手动管理图形,则应在完成位图操作后通过调用 Bitmap.recycle 释放位图,并立即舍弃 Bitmap 引用,而不是依赖垃圾回收。

其他提示和技巧

本部分列出了在处理图形时可用于提高应用性能的其他几种方法。

请勿将大型图片与 AAB/APK 文件打包在一起

导致应用下载大小较大的一个主要原因就是在 AAB 或 APK 文件中打包了图形。使用 APK 分析器工具确保打包的文件大小未超过所需的图片文件大小。请缩减图片大小或考虑将图片放置在服务器上,并仅在需要时下载这些图片。

查找冗余位图

如果您有同一张图片的多个副本,就会浪费内存。您可以使用 Android Studio 性能分析器来识别冗余图形。使用堆转储分析器捕获堆转储,然后选择重复位图设置,按此设置过滤结果。

使用 ImageBitmap 时,在绘制前调用 prepareToDraw

使用 ImageBitmap 时,如需开始将纹理上传至 GPU,请先调用 ImageBitmap#prepareToDraw(),然后再实际开始绘制。这有助于 GPU 准备纹理并提升在屏幕上显示视觉效果的性能。大多数图片加载库都已经执行此项优化,但如果您要自行使用 ImageBitmap 类,请谨记这一要点。

最好将 Int DrawableRes 或网址作为参数(而不是 Painter)传递给可组合项

由于处理图片的过程非常复杂(例如,为 Bitmaps 编写 equals 函数的计算开销非常大),因此 Painter API 未明确使用 @Stable 注释标记为稳定。不稳定的类可能会导致不必要的重组,这是因为编译器无法轻松推断数据是否发生了更改。

因此,我们建议将网址或可绘制资源 ID 作为参数传递给可组合函数,而不是传递 Painter 作为参数。

// Prefer this:
@Composable
fun MyImage(url: String) {

}
// Over this:
@Composable
fun MyImage(painter: Painter) {

}