由于各种原因,有时会build再次调用我的小部件的方法。
build
我知道这是因为父母更新了。但这会导致不良后果。导致问题的典型情况是使用FutureBuilder这种方式:
FutureBuilder
@override Widget build(BuildContext context) { return FutureBuilder( future: httpCall(), builder: (context, snapshot) { // create some layout here }, ); }
在此示例中,如果再次调用 build 方法,它将触发另一个http请求。这是不希望的。
考虑到这一点,如何处理不必要的构建?有什么办法可以防止构建调用吗?
该 构建 方法的设计是这样一种方式,它应该是 纯/无副作用 。这是因为许多外部因素都可以触发新的小部件构建,例如:
Class.of(context)
这意味着该build方法应该 不会 触发HTTP调用或修改任何状态。
这与问题有什么关系?
您面临的问题是您的构建方法有副作用/不是纯粹的,这使多余的构建调用变得很麻烦。
不应阻止构建调用,而应使构建方法纯净,以便可以在没有影响的情况下随时调用它。
在您的例子中,你会改变你的工具到一个StatefulWidget然后解压缩HTTP调用initState你的State:
StatefulWidget
initState
State
class Example extends StatefulWidget { @override _ExampleState createState() => _ExampleState(); } class _ExampleState extends State<Example> { Future<int> future; @override void initState() { future = Future.value(42); super.initState(); } @override Widget build(BuildContext context) { return FutureBuilder( future: future, builder: (context, snapshot) { // create some layout here }, ); } }
我已经知道了 我来这里是因为我 真的 很想优化重建
也有可能使小部件能够重建而无需强迫其子代进行构建。
当窗口小部件的实例保持不变时;Flutter故意不会重建孩子。这意味着您可以缓存小部件树的一部分,以防止不必要的重建。
最简单的方法是使用dart const构造函数:
const
@override Widget build(BuildContext context) { return const DecoratedBox( decoration: BoxDecoration(), child: Text("Hello World"), ); }
多亏了该const关键字,DecoratedBox即使调用了数百次构建,的实例也将保持不变。
DecoratedBox
但是您可以手动实现相同的结果:
@override Widget build(BuildContext context) { final subtree = MyWidget( child: Text("Hello World") ); return StreamBuilder<String>( stream: stream, initialData: "Foo", builder: (context, snapshot) { return Column( children: <Widget>[ Text(snapshot.data), subtree, ], ); }, ); }
在此示例中,当StreamBuilder收到新值的通知时,subtree即使StreamBuilder / Column这样做也不会重建。发生这种情况的原因是,由于有了闭包,的实例MyWidget没有改变。
subtree
MyWidget
动画中经常使用这种模式。通常的用途是AnimatedBuilder和所有过渡,例如AlignTransition。
AnimatedBuilder
AlignTransition
您也可以将其存储subtree到班级的某个字段中,尽管不建议这样做,因为它会破坏热重装功能。