以下文章来源于Flutter社区,作者talisk
通常来说,Flutter 技术构建的应用程序在默认情况下都是高性能的。所以你只需要避开常见的陷阱,就可以获得优异的性能,而不需要使用复杂的分析工具对细节做优化。这些最佳建议将ben
1. 最佳实践
如何设计一个能最有效地渲染页面的 Flutter 应用程序?特别是如何确保底层框架生成的绘图代码尽可能高效?这里有几件需要你在设计应用时考虑的事情:
1.1 控制 build() 方法的耗时
build()
方法中进行重复且耗时的工作,因为当父 Widget 重建时,子 Wdiget 的 build()
方法会被频繁地调用。build()
方法中返回一个过于庞大的 Widget。把他们分拆成不同的 Widget,并进行封装,另外他们要这样改变:setState()
时,所有后代 Widget 都将重建。因此,将 setState()
的调用转移到其 UI 实际需要更改的 Widget 子树部分。如果改变的部分仅包含在 Widget 树的一小部分中,请避免在 Widget 树的更高层级中调用 setState()
。另见:
StatefulWidget
API 文档的 Performance considerations 部分。1.2 仅当需要的时候才应用效果
由于代价很大,请谨慎使用效果。一些效果的背后调用了性能代价很大的 saveLayer()
方法。
调用 saveLayer()
会开辟一片离屏缓冲区。将内容绘制到离屏缓冲区可能会触发渲染目标切换,这些切换在较早期的 GPU 中特别慢。
一些在使用效果时的通用规则:
Opacity
Widget,就尽量不要用。有关将透明度直接应用于图像的示例,请参见 Transparent image,这比使用 Opacity widget 更快。saveLayer()
(除非明确使用 Clip.antiAliasWithSaveLayer
),因此这些操作没有 Opacity 那么耗时,但仍然很耗时,所以请谨慎使用。其他会触发 saveLayer()
的 widget,可能也会代价高昂。
ShaderMask
ColorFilter
Chip
— 当 disabledColorAlpha != 0xff
的时候,会调用 saveLayer()
Text
—might cause call to saveLayer()
if there’s an overflowShader
[Text][]— 当有 overflowShader
时,会调用 saveLayer()
避免调用 saveLayer()
的方式:
Opacity
文档。borderRadius
属性。1.3 对列表和网格列表懒加载
在构建大型网格或列表时,使用带有回调的惰性方法。这样,只有屏幕的可见部分是在开始时构建的。
请参阅:
Creating a ListView that loads one page at a time
Listview.builder
API由于构建和渲染有两个独立的线程,因此构建时间为 16ms,60Hz 显示器上渲染时间为 16ms。如果需要考虑延迟,就要在 16ms 或更短 的时间内构建和显示帧。请注意,这意味着构建需要少于 8ms,渲染也需要少于 8ms,总计 16ms 或更短。如果需要考虑丢帧(jankyness),那么每个构建和渲染阶段的 16ms 都可以。
如果在 profile 构建 状态下,每一帧渲染时间低于 16ms,你可能不必担心性能问题以及一些性能陷阱,但仍然应该致力于尽可能快地渲染每一帧。为什么?
如果你想弄明白为什么 60fps 会带来平滑的视觉体验,请看视频 Why 60fps?
2. 陷阱
如果你需要调整应用程序的性能,或者 UI 顺畅度没达到你的预期,那么 IDE 的 Flutter plugin 可以提供帮助。在 Flutter Performance 窗口中,勾选 Show widget rebuild information 复选框。此功能可帮助你检测帧的渲染和显示时间是否超过 16ms。在可能的情况下,插件提供指向相关提示的链接。
以下行为可能会对您应用的性能产生负面影响。
Opacity
widget,尤其是在动画中避免使用。请用 AnimatedOpacity
或 FadeInImage
进行代替。更多信息,请参阅 Performance considerations for opacity animation
。Column()
或 ListView()
),以避免构建成本。