Flutter 性能最佳实践

3,910 阅读5分钟

总体概述

为什么应用程序中的性能问题如此重要?

让我们看看 PedidosYa 的例子。如果您在 2021 年初打开 PedidosYa 应用程序,您可能会对加载时间感到沮丧。这是可以理解的,因为第一页在 Android 和 iOS 用户之间平均花费大约 17 秒。

1112

PedidosYa之家的问题主要在于以下几点:

  • 该页面的加载需要大量上下文信息,以便应用程序的所有其他流程在被调用时都能正常工作。
  • 该屏幕的大部分业务逻辑都在前端,这使得迭代任何行为都非常耗时。

他们所做的是,大部分责任都交给了后端,而移动应用程序只知道如何绘制每个组件。换句话说,一切都由服务协调,最终决定在屏幕上绘制什么,以什么顺序放置这些组件以及何时加载该内容。在这里你可以阅读这篇文章。

显然这都是多团队的努力,但我们在移动开发方面可以做的就是应用最佳实践来为用户提供最佳体验。

Flutter性能

Flutter 应用程序默认情况下是高性能的,因此您只需避免常见的陷阱即可获得出色的性能。您设计和实现应用程序 UI 的方式对其运行效率有很大影响。

这些最佳实践建议将帮助您编写尽可能高性能的 Flutter 应用程序。

控制build()成本

在设计 UI 时,请记住以下几点:

  • 避免在 build() 方法中进行重复且代价高昂的工作,因为 build() 可以在祖先部件重建时被频繁调用。

    34

  • 避免使用大型 build() 函数的过大的单个widget。根据封装以及它们的变化方式将它们分成不同的widget

  • 当在 State 对象上调用 setState() 时,所有后代widget都会重建。因此,将 setState() 调用定位到 UI 实际需要更改的子树部分。如果更改包含在树的一小部分,请避免在树的高处调用 setState()。

让我们看看这个例子,我们希望当用户按下图标时,只有这个图标的颜色发生变化。

5

因此,如果我们将所有这些 UI 都放在一个小部件中,当按下图标时,它将更新整个 UI。我们能做的就是把图标分离成一个StatefulWidget。

67

  • 尽可能在小部件上使用 const 构造函数,因为它们允许 Flutter 缩短大部分重建工作。要在可能的情况下自动提醒使用 const,请从flutter_lints包中启用推荐的 lints。

8

  • 要创建可重用的 UI 片段,更喜欢使用 StatelessWidget 而不是函数。

    910

    正如 Riverpod、Provider 和其他软件包的创建者 Remi Rousselet 所说。“类有更好的默认行为。方法的唯一好处是可以少写一点代码。没有功能性好处”

    尽量减少不透明度和剪裁的使用

    不透明度是另一个昂贵的操作。以下是您可能会发现有用的一些提示。

    • 仅在必要时使用不透明度widget。

13

  • 要在图像中实现淡入淡出,请考虑使用 FadeInImage
  • 要创建带圆角的矩形,而不是应用剪切矩形,请考虑使用许多小部件类提供的 borderRadius 属性。
  • 使用 SizedBox 而不是 Container

有多个用例需要使用占位符。这是下面的理想示例:

14

Container 是一个很棒的widget,您将在 Flutter 中广泛使用它。Container() 扩展以适应父级给定的约束,并且不是 const 构造函数。

相反,SizedBox 是一个 const 构造函数并构建一个固定大小的框。width 和 height 参数可以为 null 以指定框的大小不应限制在相应的维度中。

因此,当我们必须实现占位符时,应该使用 SizedBox 而不是使用容器。

深思熟虑地实施Grid和List

您的网格和列表的实施方式可能会导致您的应用出现性能问题。

15

构建大型网格或列表时,使用带有回调的惰性构建器方法。这确保在启动时只构建屏幕的可见部分。

1617

要指定每个项目的范围,您可以使用 itemExtent 或 prototypeItem。指定任何一个都比让子级确定自己的范围更有效,因为滚动机制可以利用对子级范围的预知来节省工作,例如当滚动位置急剧变化时。

没有人谈论 Flutter:Theme.of(context)

最后,我们要聊一个在 Flutter 社区很少有人聊的话题。

在一个应用程序中,我们发现我们有奇怪的行为,并且该应用程序被重建了多次。发生了什么事?让我们看一个例子来理解它。

18

当我们按下 FAB 时,我们看到 build() 方法被执行了 11 次。这是我们不希望在我们的应用程序中发生并影响性能的事情。

1920

所以我们不知道这是否是一种期望的行为,如果谷歌真的希望 Theme.of(context) 以反应方式工作(可以说),或者我们错误地使用了框架,或者这是一个很少被谈论的错误. 事实上,使用 Theme.of(context) 并不是一个坏习惯,因为通过这种方式我们可以全局访问应用程序的当前主题。

Flutter Issue中存在问题,但直到此时,Flutter 还没有官方声明。

我们该如何解决?为此,我们可以开始应用之前的建议,这不是我发明的东西,但它们是 Flutter 本身为我们提供的指导方针,以获得更好的性能。

2122

23

正如我们所见,应用这些简单的建议我们可以获得更好的性能。这似乎不是一个大的变化,但想象一下我们制作这个简单应用程序的效率如何,它不再像以前那样重建 11 次,但现在它只重建一次,这是期望和预期的行为。

因此,作为对所有在其应用程序中使用 Flutter 的人的建议,请检查使用 Theme.of(context) 是否会导致应用程序多次重建,因为正如我所说,以这种方式访问主题并尝试应用是很常见的我们审查的良好做法。