StatefulWidget 和 StatelessWidget 的 Flutter 性能

Posted

技术标签:

【中文标题】StatefulWidget 和 StatelessWidget 的 Flutter 性能【英文标题】:Flutter performance of StatefulWidget and StatelessWidget 【发布时间】:2020-04-06 03:32:50 【问题描述】:

当我必须创建在我的应用程序中多次使用的小部件“模板”时,我会使用很多 StatelessWidgets,因为文档是这样说的:

无状态小部件在您作为用户界面的一部分时很有用 所描述的不依赖于除 对象本身和BuildContext中的配置信息 小部件被膨胀了。

这是一个例子:

class StepInputButton extends StatelessWidget 

  final int pos;
  final String value;

  const StepInputButton(
    this.pos,
    this.value
  );

  @override
  Widget build(BuildContext context) 
    return Row(
      // Text, Icon and a tiny button
    );
  


以上内容很好,因为我可以在带有 CONST 的代码中使用 const StepInputButton(val, "val"), 来提高性能。


问题

我使用著名的Provider 小部件来管理状态,我的应用程序的页面通常如下所示:

class SuccessPage extends StatelessWidget 

  @override
  Widget build(BuildContext context) 
    var prov = Provider.of<Type>(context);    
    return Scaffold(...); 
  


这是我的带有 Scaffold 的应用程序的页面,它有一个抽屉、一个浮动操作按钮和一个 appTitle。 在这里,我使用 StatelessWidget 因为我不使用 setState(),因为提供程序为我完成了所有工作。但他们仍然在官方的颤振文档中说:

对于可以动态变化的组合,例如由于有一个 内部时钟驱动状态,或取决于某些系统状态, 考虑使用 StatefulWidget。

所以我必须将class SuccessPage extends StatelessWidget 更改为class SuccessPage extends StatefulWidget 吗?我有优势吗?

注意:如果您想以另一种方式提出问题:我是否应该使用 StatefulWidgets 来创建状态将要发生变化的“应用程序页面”,而使用 StatelessWidgets 来创建状态不会发生变化的“可重用小部件”?不改?

【问题讨论】:

【参考方案1】:

StatefulWidget 在小部件本身保持自己的状态时是必需的。在您给出的示例中,Provider 包正在为您处理状态,假设您在小部件树的上层使用正确的提供程序类型(例如,ChangeNotifierProvider)。这段代码中似乎也没有任何东西可以从访问小部件的生命周期中受益,因此您不需要访问像initStatedispose 这样的方法。

因此,小部件本身无需管理任何内容,因此无需将您的类转换为有状态的。

不过,我可能建议的一件事是使用Consumer 而不是直接调用Provider.ofConsumer 会为您处理呼叫,并消除在 Provider 检测到状态更改时您的小部件是否会更新的任何歧义。

【讨论】:

非常感谢,您已经准确地告诉了我我需要什么。我不需要访问状态,因为 Provider 正在为我做这件事,所以我会去无状态 @Abion47,如果我需要使用表单输入数据(并在单击保存按钮后将数据记录到休息服务器),我应该去StatefulWidget还是我也可以这样做一切都使用适当的提供者和StatelessWidget ? @Cristiano 如果您指的是提供程序包中的提供程序,那么您使用的Consumer 本身就是一个StatefulWidget,它在状态更改时处理重建,因此如果您通过提供者/消费者然后是的,您的表单小部件可以是无状态的。 @Abion47,你提到的Provider.of 的含糊之处是什么? @TiagoSantos 关于在调用Provider.of 时是否会更新小部件的歧义。 (实际上没有任何继承的小部件遵循一组关于其更改是否会更新小部件的规则,但这些规则有时可能难以理解。如果有任何疑问,请改用Consumer。) 【参考方案2】:

保持简单:

    如果您的小部件中有final 全局变量,那么您需要一个StatefulWidget 如果所有全局变量都是final,那么你应该使用StatelessWidget

原因:

    如果您的全局变量不是最终的,这意味着它可以更改,如果它的值发生更改,则意味着您的对象(小部件)的状态已更改(我正在谈论的基本 oops 概念)。在这种情况下,您希望调用小部件的 build 方法,以便您的更改应用到 UI 上(如果它对您的 UI 很重要)。我们通过调用 setState(); 来实现,因此我们将 StatefulWidget 用于此类用例。 如果在构造函数中初始化全局变量就足够了,以后就不需要为它分配任何值,那么在这种情况下使用StatelessWidget

我尽量保持它非常简单且技术性不够,所以如果您仍有任何疑问,请对此答案发表评论

【讨论】:

很好的解释,我明白你应该得到 +1。因此,在我的情况下,SuccessPage 作为 StatelessWidget 很好,因为我没有非最终变量,并且状态是在外部处理的。对吗?【参考方案3】:

您将StatelessWidget 用于不改变其状态的小部件,这些小部件将始终保持不变。例如,appBar 是无状态的。StatelessWidgetbuild(...) 函数只被调用一次,任何Variable(s)Value(s)Event(s) 中的任何更改都不能再次调用它。

因此,当您需要更改状态(ex 值)然后使用StatefulWidgets,基本上StatelessWidget 用于构建静态 UI 小部件

【讨论】:

以上是关于StatefulWidget 和 StatelessWidget 的 Flutter 性能的主要内容,如果未能解决你的问题,请参考以下文章

Flutter控件——常用控件:StatefulWidget与State

StatelessWidget和StatefulWidget的区别

StatefulBuilder 与 StatefulWidget

StatefulWidget 和 StatelessWidget 的 Flutter 性能

为啥父 StatefulWidget 中的 setState 不更新子 StatefulWidget [重复]

Flutter StatefulWidget 带参数