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;

}

这段代码按预期工作,但是在从中获取价值时遇到了问题Future

案例场景:我将数据存储在本地数据库中,并试图在listview中显示它。我正在使用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(),
                );
        }));

}

移入return Scaffold(.....)内部.then无效。因为小部件构建不返回任何内容。

我发现的另一个选项是async/await但最后还是相同的问题,下面提供了代码:

_getImagesPath() async {
    return await imgPath();
}

调用_getImagesPath()return Future,而不是实际数据。

我相信这里有一个很小的逻辑错误,但我自己却找不到。

珍娜·雷迪

我看到您必须从两个Future的输出中构建窗口小部件。您可以使用两种FutureBuilders方法,也可以使用辅助方法将它们组合为一个简化的代码单元。

另外,切勿从build函数计算/调用异步函数。必须先对其进行初始化(在构造函数或initState方法中),否则该小部件可能最终永久重新绘制自身。

解决方案:为了简化代码,最好将两个将来的输出合并到一个类中,如下例所示:

build方法所需的数据


class DataRequiredForBuild {
  String imagesPath;
  List items;

  DataRequiredForBuild({
    this.imagesPath,
    this.items,
  });
}

获取所有必需数据的功能:


Future<DataRequiredForBuild> _fetchAllData() async {
  return DataRequiredForBuild(
    imagesPath: await getImagesPath(),
    items: await databaseHelperGetList(),
  );
}

现在将所有内容放到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(),
              );
      },
    ),
  );
}

希望能帮助到你。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章