flutter - FutureBuilder 不等待异步函数加载
问题描述
编辑3:这就是现在的样子
@override
void initState() {
super.initState();
myFuture = genCode();
}
Future<Uint8List> genCode() async {
print('This should be the start')
Obj o = await _getAsyncData();
print('This should be the end');
return await scanner.generateBarCode(o.str);
}
Future<Obj> _getAsyncData() async {
Obj o = await addObj();
print('Hello');
print(o.str);
return o;
}
Future<Obj> addObj() async {
final String url = 'APIURL';
final client = new http.Client();
final response = await client.post(
url,
headers: {HttpHeaders.contentTypeHeader: 'application/json',
);
print('Obj added. Received response.');
Obj o = Obj.fromJSON(json.decode(response.body));
print(o.str);
return o;
}
印刷
I/flutter (12991): This should be the start
I/flutter (12991): This should be the end
I/flutter (12991): Obj added. Received response.
I/flutter (12991): 12345
I/flutter (12991): Hello
I/flutter (12991): 12345
FutureBuilder 小部件直接进入这段代码
if (snapshot.hasError) {
children = <Widget>[
Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
)
];
}
它显示感叹号并在屏幕上打印:
Error: NoSuchMethodError: The getter 'str' was called on null.
Receiver: null
Tried calling: str
不知何故,它忽略了异步函数仍在后台运行的事实。
FutureBuilder(
future: myFuture, // a previously-obtained Future<String> or null
builder: (BuildContext context, AsyncSnapshot snapshot) {
List<Widget> children;
if (snapshot.hasData) {
children = <Widget>[
QRDisplayWidget(title: '', bytes: snapshot.data),
];
} else if (snapshot.hasError) {
children = <Widget>[
Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
)
];
} else {
children = <Widget>[
SizedBox(
child: CircularProgressIndicator(),
width: 60,
height: 60,
),
const Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
];
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
),
);
},
),
原始代码:
错误:无法将参数类型“Future Function(BuildContext, AsyncSnapshot)”分配给参数类型“Widget Function(BuildContext, AsyncSnapshot)”。
我错过了什么?代码与文档完全相同
FutureBuilder<String>(
future: getQRStr(), // a previously-obtained Future<String> or null
builder: (BuildContext context, AsyncSnapshot<String> snapshot) async {
List<Widget> children;
if (snapshot.hasData) {
children = <Widget>[
QRDisplayWidget(title: '', bytes: getBytes(snapshot)),
];
} else if (snapshot.hasError) {
children = <Widget>[
Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
)
];
} else {
children = <Widget>[
SizedBox(
child: CircularProgressIndicator(),
width: 60,
height: 60,
),
const Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
];
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
),
);
},
),
编辑:所以我让 FutureBuilder 停止抛出错误,但在获取数据之前仍会检索 String 值。
Future<String> getQRStr() async{
String str = await _asyncFetchData();
return Future.value(str); // return your response
}
Future<Uint8List> getBytes(AsyncSnapshot snapshot) async{
return await scanner.generateBarCode(snapshot.data);
}
编辑2:我将其编辑为我现在所拥有的。如果我在 getBytes 上使用 Future,我会得到Error: The argument type 'Future<Uint8List>' can't be assigned to the parameter type 'Uint8List'
. 删除 Future 使其运行编译没有错误,但应用程序似乎陷入了永久刷新的状态,不断调用 getQRStr()。
在 _asyncFetchData 函数下,我有一个打印函数,它在成功检索数据后打印数据,然后返回值。那打印得很好。但是 FutureBuilder 打印出返回的值为空。
解决方案
您不能将 a传递Future
给. 你不能在.builder
FutureBuilder
await
builder
作为一种解决方案,您可以创建一个如下所示的新函数并将其传递给FutureBuilder
.
Future<Uint8List> genCode() async {
return await scanner.generateBarCode(await getQRStr());
}
其他部分:
@override
void initState() {
super.initState();
myFuture = genCode();
}
......
FutureBuilder(
future: myFuture,
builder: (BuildContext context, AsyncSnapshot snapshot) {
List<Widget> children;
if (snapshot.hasData) {
children = <Widget>[
QRDisplayWidget(title: '', bytes: snapshot.data),
];
} else if (snapshot.hasError) {
children = <Widget>[
Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
)
];
} else {
children = <Widget>[
SizedBox(
child: CircularProgressIndicator(),
width: 60,
height: 60,
),
const Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
];
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
),
);
},
),
推荐阅读
- python - 如何使用 Keract 显示不同的 CNN 激活?
- python - ThreadPoolExecutor 完成后 Python 进程退出而没有警告或错误
- sql - 为什么我的 datediff 表达式的输出要返回括号中的天数?
- php - 相同的键需要两个数组索引 - PHP
- c# - 游戏视图中不显示子弹
- excel - 宏 VBA 的调度部分
- php - 如何转换 \u009
- amazon-s3 - 将数据从 QlikSense 云导出到 AWS S3 存储桶
- keras - 如何在预训练模型中的每个 conv2d 层之后循环添加 BatchNormalization
- postgresql - 有没有人设法使用 Direct to SwiftUI 运行 DVDRental 示例?