Ale*_*ena 8 asynchronous future async-await dart flutter
我有一个返回图像目录路径的函数,它执行一些额外的检查,比如目录是否存在,然后它会相应地运行。
这是我的代码:
Future<String> getImagesPath() async {
final Directory appDir = await getApplicationDocumentsDirectory();
final String appDirPath = appDir.path;
final String imgPath = appDirPath + '/data/images';
final imgDir = new Directory(imgPath);
bool dirExists = await imgDir.exists();
if (!dirExists) {
await new Directory(imgPath).create(recursive: true);
}
return imgPath;
}
Run Code Online (Sandbox Code Playgroud)
这段代码按预期工作,但我在从Future
.
案例场景:
我将数据存储在本地数据库中并尝试在列表视图中显示它。我正在使用FutureBuilder
,如本答案中所述。每个数据行都有一个与之相连的图像(连接意味着,图像名称存储在db中)。
内部Widget build
方法,我有这个代码:
@override
Widget build(BuildContext context) {
getImagesPath().then((path){
imagesPath = path;
print(imagesPath); //prints correct path
});
print(imagesPath); //prints null
return Scaffold(
//removed
body: FutureBuilder<List>(
future: databaseHelper.getList(),
initialData: List(),
builder: (context, snapshot) {
return snapshot.hasData
? ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (_, int position) {
final item = snapshot.data[position];
final image = "$imagesPath/${item.row[0]}.jpg";
return Card(
child: ListTile(
leading: Image.asset(image),
title: Text(item.row[1]),
subtitle: Text(item.row[2]),
trailing: Icon(Icons.launch),
));
})
: Center(
child: CircularProgressIndicator(),
);
}));
Run Code Online (Sandbox Code Playgroud)
}
return Scaffold(.....)
内部转移.then
不起作用。因为小部件构建不返回任何内容。
我发现的另一个选项是async/await
但最后,同样的问题,代码如下:
_getImagesPath() async {
return await imgPath();
}
Run Code Online (Sandbox Code Playgroud)
调用_getImagesPath()
返回Future
,而不是实际数据。
我相信有很小的逻辑错误,但我自己找不到。
Che*_*ddy 10
我看到您必须从两个期货的输出中构建您的小部件。您可以使用两个FutureBuilders
或使用辅助方法将它们组合成一个简化的代码单元。
此外,永远不要从build
函数计算/调用异步函数。它必须在之前(在构造函数或initState
方法中)初始化,否则小部件可能最终会永远重新绘制自己。
来到解决方案:为了简化代码,最好将两个未来的输出组合到一个类中,如下例所示:
build
方法所需数据:
class DataRequiredForBuild {
String imagesPath;
List items;
DataRequiredForBuild({
this.imagesPath,
this.items,
});
}
Run Code Online (Sandbox Code Playgroud)
获取所有必需数据的函数:
Future<DataRequiredForBuild> _fetchAllData() async {
return DataRequiredForBuild(
imagesPath: await getImagesPath(),
items: await databaseHelperGetList(),
);
}
Run Code Online (Sandbox Code Playgroud)
现在将所有内容放在 Widget 中:
Future<DataRequiredForBuild> _dataRequiredForBuild;
@override
void initState() {
super.initState();
// this should not be done in build method.
_dataRequiredForBuild = _fetchAllData();
}
@override
Widget build(BuildContext context) {
return Scaffold(
//removed
body: FutureBuilder<DataRequiredForBuild>(
future: _dataRequiredForBuild,
builder: (context, snapshot) {
return snapshot.hasData
? ListView.builder(
itemCount: snapshot.data.items.length,
itemBuilder: (_, int position) {
final item = snapshot.data.items[position];
final image = "${snapshot.data.imagesPath}/${item.row[0]}.jpg";
return Card(
child: ListTile(
leading: Image.asset(image),
title: Text(item.row[1]),
subtitle: Text(item.row[2]),
trailing: Icon(Icons.launch),
));
})
: Center(
child: CircularProgressIndicator(),
);
},
),
);
}
Run Code Online (Sandbox Code Playgroud)
希望能帮助到你。
将这段代码移入内部FutureBuilder
应该可以解决问题。
getImagesPath().then((path){
imagesPath = path;
print(imagesPath); //prints correct path
});
Run Code Online (Sandbox Code Playgroud)
所以你的最终代码应该如下所示:
@override
Widget build(BuildContext context) {
return Scaffold(
//removed
body: FutureBuilder<List>(
future: databaseHelper.getList(),
initialData: List(),
builder: (context, snapshot) {
return snapshot.hasData
? ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (_, int position) {
getImagesPath().then((path){
imagesPath = path;
});
final item = snapshot.data[position];
final image = "$imagesPath/${item.row[0]}.jpg";
return Card(
child: ListTile(
leading: Image.file(File(image)),
title: Text(item.row[1]),
subtitle: Text(item.row[2]),
trailing: Icon(Icons.launch),
));
})
: Center(
child: CircularProgressIndicator(),
);
}));
}
Run Code Online (Sandbox Code Playgroud)
希望能帮助到你!
归档时间: |
|
查看次数: |
19652 次 |
最近记录: |