我不希望每次重新构建小部件时都触发异步调用。 因此,我在initState中调用了异步函数。
在initState中调用异步
ccache
使用FutureBuilder
@override
void initState() {
someAsyncCall().then((result) {
setState() {
_result = result;
}
});
}
@override
Widget build(BuildContext context) {
if (_result == null) {
reutrn new Container();
}
return new SomeWidget();
}
两种解决方案都有副作用或不良做法吗?
我修改了演示应用程序,以解释为什么我要在initSate中调用异步。
1.打开应用,打印主画面
2.推动屏幕测试,打印测试,主
3.弹出测试,打印主画面
如果我在构建中调用异步函数,它将调用3次。
我想要的是,除非主要处理/弹出,否则我需要一次异步函数调用。
根据RémiRousselet的回答,在initState中调用异步是一种问题或错误。
那么,如何确保异步函数调用一次?
@override
void initState() {
_future = someAsyncCall();
}
@override
Widget build(BuildContext context) {
return new FutureBuilder(
future: _future,
builder: // do something
);
}
我需要做类似
@override
Widget build(BuildContext context) {
print("build main");
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new RaisedButton(onPressed: () {
Navigator.push(context, new MaterialPageRoute(builder: (context) {
return new Test();
}));
}),
],
),
)
);
}
class Test extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("build Test");
return new Scaffold(
body:
new FlatButton(onPressed: () {
Navigator.pop(context);
}, child: new Text("back"))
);
}
}
答案 0 :(得分:1)
虽然有些冗长,但FutureBuilder
绝对是解决之道。
在initState中调用异步函数,然后在完成时执行setState
会遇到一些问题。在大多数情况下,您不必担心错误捕获或处理加载时间。
请记住,Flutter希望initState
是同步的。因此,虽然dart不会阻止您对同步函数进行异步调用,但flutter很可能会在未准备就绪时认为您的小部件已准备就绪。
答案 1 :(得分:0)
我会选择第一种样式,因为我可以控制等待时发生的情况。这取决于您要从应用程序中获得什么,我更喜欢清晰的“正在加载”消息,而不是不知道它是否卡住或正在加载。
谈到副作用,您可以看到他们对FutureBuilder的看法
此操作的副作用是,为FutureBuilder提供新的但已经完成的将来将导致ConnectionState.waiting状态中的单个帧。这是因为无法同步确定Future已经完成。
答案 2 :(得分:0)
我可以在异步函数的末尾做一个空的setState()。
这将使写入排队,以便仅在所有异步工作完成后才能看到它们的视觉效果。但是,队列将不可靠。应用中的其他内容可能会导致小部件重建,在这种情况下,您将看到单个写入的效果。
或者我可以将每个单独的分配包装到其自己的setState中:使用一个临时值等待getCustomValue();然后将其分配给setState内的值。
这将确保您看到每个增量状态更改的可视更新(假设异步任务之间有足够的时间来放置框架)。
我应该和谁一起去? 中间状态对用户有意义吗?具体来说,您是否要确保在执行此一系列操作时,应用程序的外观更新?相反,您是否要阻止中间状态显示给用户?
如果您希望用户看到中间状态,则可能希望将每个写入包装在setState调用中。如果要防止显示中间状态,则可能希望将写入实际上排入队列,并使它们全部在一系列异步操作的结尾自动发生。
在函数的末尾放置单个setState会使这两个世界变得更糟,因为根据应用程序中发生的其他情况,中间状态将是任意可见的。在最坏的情况下,中间状态可能是越野车,并且难以复制。
有更好的解决方案吗?
假设您要等待所有操作完成,然后以原子方式更新对象的状态,我建议让异步对象返回所有状态变化的表示。异步操作完成后,我将在单个setState调用中将所有更改同步提交给您的状态。这样可以自动改变您的状态,并确保应用程序的外观得到更新。
要考虑的另一个问题是,当异步操作挂起时,如果从树中删除窗口小部件会发生什么。理想情况下,您可以取消异步操作以节省资源,但是如果这不是一个选择,则可能要在提交更改之前检查State对象上已装入的布尔值。
来自:3951#issue