Flutter 之StatelessWidget和StatefulWidget区别及使用详解

298 阅读3分钟

在[Flutter]中,widget分为两类:Stateful(有状态)stateless(无状态)widget。

stateless widget 没有内部状态,Icon、IconButton, 和Text都是无状态widget, 它们都是 StatelessWidget的[子类]。

stateful widget 是动态的,用户可以和其交互(例如输入一个表单、 或者移动一个slider滑块),或者可以随时间改变 (也许是数据改变导致的UI更新)。Checkbox, Radio, Slider, InkWell, Form, and TextField 都是 stateful widgets, 它们都是 StatefulWidget的子类。

StatelessWidget

StatelessWidgets 是不可变的, 这意味着它们的属性不能改变——所有的值都是最终的。 如果无状态Widget里面有子Widget,并且子Widget是有状态的,则子Widget的内容是可以通过setState来更改的。无状态Widget影响的仅仅是自己是无状态的,不回影响他的父Widget和子Widget。

StatefulWidget

Stateful widgets 持有的状态可能在widget生命周期中发生变化

状态是什么?状态是在构建控件时可以同步读取的信息,并且在控件的生命周期内可以改变,控件的使用者应该在状态发生变化时使用**State.setState**方法及时通知框架

StatefulWidget有两种不同的类型:

  • 第一种是在State.initState中分配资源,并将其置于State.dispose中释放,而且不依赖于InheritedWidget或调用State.setState。这样的控件通常在应用程序或页面的根部使用,并通过ChangeNotifierStream或其他这样的对象与子控件通信。遵循这种模式的有状态控件相对便宜(在CPU和GPU周期方面),因为它们是一次构建的,而且不会更新。因此,它们可以实现一些非常复杂的build方法。

  • 第二种是使用State.setState或依赖于InheritedWidget的控件。这些控件通常会在应用程序的生命周期中重新构建很多次,因此降低重新构建这种控件的影响至关重要。实际上,它们也可以使用State.initStateState.didChangeDependencies来分配资源,但重点是它们要重新构建。 有以下做法可以用于减少重新构建有状态控件的影响:

  • 把状态推到树叶上。例如,我们的页面上有一个嘀嗒嘀嗒的时钟,此时不应该将状态置于页面的顶部,因为这样的话,每当时钟嘀嗒时,整个页面都会重新构建。我们应该创建一个专用的时钟控件,这样只会更新它自己。

  • 尽可能减少**build方法传递创建的节点数量及其创建的任何控件。理想情况下,有状态的控件只会创建一个控件,而这个控件将是一个RenderObjectWidget**。很显然,在实际开发中,我们不一定能做到这一点,但控件越接近这个理想状态,效率就越高。

  • 如果子树不更改,则缓存表示该子树的控件,并在每次使用该子树时重新使用它。重用控件的效率要比创建新的控件要高效得多,将有状态的部分分解成一个带有子参数的控件是这样做的常见方法。

  • 尽可能使用**const**修饰控件,这相当于缓存一个控件,并重新使用它。

关于有状态与无状态的选择

  • 自定义StatelessWidget 
如果自定义的控件仅依赖于对象本身的配置信息,仅仅是用于展示给定的信息。那我们应该选择使用StatelessWidget创建一个无状态控件。

自定义StatefulWidget

如果自定义的控件可以与用户进行交互,比如通过键盘输入内容、通过滑动屏幕移动滑块、点击时改变状态,又或者是随着时间的推移而变化,比如数据Feed会更新状态。这时我们应该选择使用StatefulWidget创建一个有状态控件。


\