优化图像性能

如果您不小心,处理图像可能会很快导致性能问题。在处理大型位图时,您很容易遇到 OutOfMemoryError。请遵循以下最佳实践,以确保您的应用获得最佳性能。

仅加载您需要的位图大小

大多数智能手机都配备了高分辨率摄像头,可生成大型图像文件。如果您要在屏幕上显示图像,则必须降低图像分辨率或仅将图像加载到图像容器的大小。持续加载比需要更大的图像可能会耗尽 GPU 缓存,从而导致 UI 渲染性能下降。

管理图像大小

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

尽可能使用矢量而不是位图

当在屏幕上以视觉方式表示某些内容时,您需要确定它是否可以表示为矢量。优先使用矢量图像而不是位图,因为它们在缩放到不同尺寸时不会出现像素化。但是,并非所有内容都可以表示为矢量 - 使用相机拍摄的图像无法转换为矢量。

为不同的屏幕尺寸提供备用资源

如果您要随应用一起提供图像,请考虑为不同的设备分辨率提供不同大小的资源。这有助于减少设备上应用的下载大小,并提高性能,因为它会在较低分辨率的设备上加载较低分辨率的图像。有关为不同设备尺寸提供备用位图的更多信息,请 查看备用位图文档

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

使用 ImageBitmap 时,要开始将纹理上传到 GPU 的过程,请在实际绘制之前调用 ImageBitmap#prepareToDraw()。这有助于 GPU 准备纹理并提高在屏幕上显示视觉效果的性能。大多数图像加载库已经执行了此优化,但如果您自己使用 ImageBitmap 类,则需要注意这一点。

优先将 Int DrawableRes 或 URL 作为参数传递到您的可组合项中,而不是 Painter

由于处理图像的复杂性(例如,为 Bitmaps 编写 equals 函数在计算上将非常昂贵),因此 Painter API 明确地未标记为 稳定 类。不稳定的类可能会导致不必要的重新组合,因为编译器无法轻松推断数据是否已更改。

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

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

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

}

不要在比需要的时间更长的时间内将位图存储在内存中

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

不要将大型图像打包到您的 AAB/APK 文件中

导致应用下载大小过大的主要原因之一是打包在 AAB 或 APK 文件中的图形。使用 APK 分析器 工具以确保您没有打包比需要更大的图像文件。减小尺寸或考虑将图像放置在服务器上,并在需要时才下载它们。