优化图片的性能

如果不小心,使用图片时可能会快速引入性能问题。使用大型位图时,您很容易遇到 OutOfMemoryError。遵循以下最佳实践可以确保您的应用达到最佳性能。

请仅加载所需大小的位图

大多数智能手机都自带高分辨率相机,能够生成非常大的图片文件。如果您要在屏幕上显示图片,则必须降低图片的分辨率,或者仅加载不超过图片容器大小的图片。持续加载超过所需大小的图片可能会耗尽 GPU 缓存,从而导致界面渲染性能不佳。

如需管理图片大小,请执行以下操作:

  • 尽可能缩小图片文件(而不影响输出图片)。
  • 请考虑将图片转换为 WEBP 格式,而不是 JPEG 或 PNG。
  • 针对不同的屏幕分辨率提供较小的图片(请参阅提示 3)。
  • 使用图片加载库,该库会按比例缩小图片的大小,以适应屏幕上的视图大小。这有助于提高屏幕的加载性能。

尽可能使用矢量而非位图

以视觉方式表示屏幕上的内容时,您需要确定它是否可以表示为矢量。首选矢量图像而非位图,因为矢量图像在缩放为不同的大小时不会像素化。不过,并非所有内容都可以表示为矢量。比如说,使用相机拍摄的图片就无法转换为矢量。

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

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

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

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

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

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

因此,最好是将网址或可绘制对象资源 ID 作为参数传递给可组合项,而不是传递 Painter 作为参数。

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

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

}

避免位图在内存中存储的时间超过所需要的时间

加载到内存中的位图越多,设备上内存耗尽的可能性就越高。例如,如果要在屏幕上加载 Image 可组合项的大型列表,请使用 LazyColumnLazyRow,以确保在滚动大型列表时释放内存。

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

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