
区别
一些思考
- 既然StatefulWidget的主要作用只是为了赋予了其自我重新构建(self rebuild)的能力,那为什么需要State呢?
Widget依赖于构造函数和Build方法中的
BuildContext中的外部信息,如果是外部触发的Build(例如:祖先Widget build),所有信息都是完整的。如果self rebuild则无法获取更新后的外部信息,所以需要内部维护一份不依赖于外部的信息,State就是这个作用。
- 既然StatefulWidget的功能更完善,为什么又提供一个StatelessWidget呢?
这个问题其实等同于为什么官方要限制我们使用self rebuild?每次Build都需要新建和销毁大量的Widget,Element Tree的diff,甚至繁重的渲染和重绘。官方推荐使用StatelessWidget,其实就是为了性能的考虑而对开发者进行的一些约束,限制开发者无节制的使用self rebuild造成的性能降低。
- 可不可以在开发中全部都使用StatefulWidget?
当然可以,但是不推荐,理由见上个问题。
- 可不可以在开发中全部都使用StatelessWidget?
如果是显示简单的不变的内容可以这样使用,但是这种场景太少了。至少在App应用中不太可能。
- 开发中如何选择StatelessWidget还是StatefulWidget?
首选StatelessWidget,当无法满足需求的时候用VS Code或者Android Stutio的快捷键将其变成StatefulWidget。
实战分享
我们前面比较了StatelessWidget和StatefulWidget的区别,进行了一些分析,到底如何写出更好更优化的代码,现在我们就用Flutter官方的计数器Demo来练练手。

Counter
通过前面的分析,我们知道点击FloatingActionButton会调用_MyHomePageState的setState进行rebuild。如下图所示:

demo_build
细心的你可能发现问题了,我只是想修改Scaffold->Body->Center->Column->第二个Text中的文字。而Build的起点是Scaffold,这么长的构建链条相当于修改一个文字,把整个页面都重新构建了一次。就显然是一个无法忽视的问题。
注意:真实的Build链条不是我上面列的这么短,因为Scaffold等都进行了封装,真实的Build得进入他们的
build方法去了解,真实的Build链条比我们代码中看到的Scaffold->Body->Center->Column->第二个Text这个逻辑复杂多了。
修改的思路就是我们只需要在第二个Text上封装一个StatefulWidget,让这个StatefulWidget的setState去触发第二个Text的文字修改。
我们抽提一个CounterText:
class CounterText extends StatefulWidget {
final _CounterTextState state = _CounterTextState();
CounterText({
Key key,
}) : super(key: key);
@override
_CounterTextState createState() => state;
}
class _CounterTextState extends State<CounterText> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Container(
child: Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
);
}
}
CounterText的使用:
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
CounterText counterText = CounterText();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
counterText,
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: counterText.state._incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
这样就改造完成了。
总结:
我们需要对StatelessWidget和StatefulWidget有一个全面的了解,才能正确的使用他们。欢迎一起探讨和学习。
文章均来自互联网如有不妥请联系作者删除QQ:314111741 地址:http://www.mqs.net/post/13092.html
添加新评论