对于万物皆Widget的Fultter,同样的事情一般都有多种控件可以实现,太多的选择总是会让人陷入或多或少的选择纠结症和对性能的忧虑上。
初次接触Flutter,首先必然要面对的两座大山:StatelessWidget & StatefulWidget。 而在这两个控件的选择上,大部分人给出的解释就是:"就像他们的名字一样,无状态静态的视图展示使用StatelessWidget,而有交互,需要动态变化的使用StatefulWidget."
这样的解释正确,但过于模糊,似乎StatelessWidget出现的地方均可以用StatefulWidget来代替,于是为了后期可能的变化、为了coding简便,StatefulWidget被滥用变成了很容易发生的事情。
所以今天我们就详细聊一下StatefulWidget和StatelessWidget的区别和使用。
StatefulWidget与StatelessWidget区别
对于普遍存在的模糊解释,想吐槽又不能说它是错的,但它确实产生了一些无解。
我个人对StatefulWidget与StatelessWidget理解:
StatelessWidget初始化之后就无法改变,如果想改变,那便需要重新创建,new另一个StatelessWidget进行替换。但StatelessWidget因为是静态的,他没有办法重新创建自己。所以StatefulWidget便提供了这样的机制,通过调用setState((){})
标记自身为dirty状态,以等待下一次系统的重绘检查。
StatefulWidget 动态化代价
通过定义,StatefulWidget怎么看都是一个万金油的存在,但是,我期望你能对StatefulWidget动态化所付出的代价有所了解:
在State类中的调用setState((){})
更新视图,将会触发State.build! 也将间接的触发其每个子Widget的构造方法以及build方法。
这意味这什么呢? 如果你的根布局是一个StatefulWidget,那么每在根State中调用一次setState((){})
,都将是一次整页所有Widget的rebuild!!! 举个栗子:
class MyStatefulWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return CustomerState();
}
}
class CustomerState extends State<MyStatefulWidget> {
int _num = 0;
@override
Widget build(BuildContext context) {
// TODO: implement build
return Row(children: <Widget>[
GestureDetector(
onTap: () {
setState(() {
_num++;
});
},
child: Text("Click My"),
),
Text("1:AAAAA"),
Text("2:BBBBB"),
Text("3:C:" + _num.toString()),
CustomerContainer()
]);
}
}
class CustomerContainer extends StatelessWidget {
@override
Widget build(BuildContext context) {
for (int i = 0; i < 1000000; i++) {
print("我是一个耗时操作 for:" + i.toString());
}
return Container(
child: Text("4:DDDD"),
);
}
}
复制代码
对于上面的代码,每一次点击 ”My Click“,CustomerState build方法,以及Row、Text、Customer