Flutter 框架

StatefulWidget 优化

StatefulWidget 的性能考略有两个主要类别:

  • 第一类是在 State.initState 中分配资源并在 State.dispose 中处置它们的小部件,但它们不依赖于 InheritedWidget 或调用 State.setState 。这些小部件通常用于应用程序或页面的根部,通过 ChangeNotifierStream 或其他类似的对象与子小部件通信。采用这种模式的有状态小部件相对较便宜(从CPU和GPU周期的角度来看),因为它们只建立一次,然后不再更新。因此,它们的构建方法可以相对复杂和深入。
  • 第二类是使用 State.setState 或依赖于 InheritedWidget 的小部件。在应用程序的生命周期中,这些小部件通常会多次重建,因此必须尽量减少重建此类部件所造成的影响。(它们也可能使用 State.initStateState.didChangeDependencies 并分配资源,但重要的是它们会重建)。)

有几种技术可以用于最小化重建有状态小部件的影响:

  • 将状态推送到叶子(末端)。例如,如果您的页面具有定时时钟,请不要将状态放在页面顶部,并在每次时钟滴答时重新构建整个页面,而是创建一个专用的时钟小部件,该小部件仅更新自身。
  • 尽量减少由构建方法及其创建的任何小部件临时创建的节点数量。在理想情况下,有状态部件只会创建一个部件,而且该部件必须是 RenderObjectWidget(渲染对象部件)。(显然,这并不总是切实可行,但部件越接近这一理想状态,效率就越高)。
  • 在可能的情况下使用 const 小部件。(这等效于缓存小部件并重复使用它。)
  • 避免改变任何已创建子树的深度或改变子树中任何部件的类型。例如,与其返回子部件或用 IgnorePointer 包裹的子部件,不如始终用 IgnorePointer 包裹子部件,并控制 IgnorePointer.ignoring 属性。这是因为更改子树的深度需要重建、布局和绘制整个子树,而只更改属性则只需对呈现树进行尽可能小的更改(例如,在 IgnorePointer 的情况下,根本不需要布局或重新绘制)。
  • 如果由于某种原因必须更改深度,请考虑将子树的常见部分包装在具有在有状态小部件的生命周期内保持一致的 GlobalKey 的小部件中。 (如果没有其他小部件可以方便地分配键,则 KeyedSubtree 小部件可能对此目的有用。)