【问题标题】:Flutter/Dart: getting directory contents with future not workingFlutter/Dart:获取目录内容但未来不工作
【发布时间】:2021-01-13 08:19:33
【问题描述】:

我正在尝试获取目录的内容并将其显示在屏幕上。

当我只有 1 个未来(并在方法中硬编码返回值)时,我能够显示它们。但是当我在未来中嵌入未来(我需要这样做以获取应用程序目录和文件列表)时,它就不起作用了。

这是我的代码:

  Future<List<CardFileInfo>> _getFilelist() {
    var localFileHelper = new LocalFileHelper();
    return Future.value(localFileHelper.getFileList());
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text("Cards")
      ),
       body: Center(
         child: Column(
           children: <Widget>[
             FutureBuilder<List<CardFileInfo>>(
               future: _getFilelist(),
               builder: (context, snapshot) {
                 if (snapshot.hasData) {
                    return Text("Files Found");
                 }
                 else {
                    return Text("Still looking");
                 }
               } //end of builder
             ), //end of future builder
           ], //end of children
         ), //end of column
       ), //end of center
    ); //end of scaffold
  } 

这里是localFileHelper.getFileList()方法的代码:

  List<CardFileInfo> getFileList() {

    List<CardFileInfo> cardInfoList = [];
    final dirName = getApplicationDocumentsDirectory();

    // *** if I uncomment the following two lines, the process works *** 
    // cardInfoList.add(CardFileInfo("dummy.tsv"));
    // return cardInfoList;

    dirName.then((dir) { // <---------- problem seems occurs here with the future
      final files = dir.list().toList();
      files.then((values){
        values.forEach((element) {
          var type = element.path.toString().split(".").last.trim();
          if (type == "tsv") {
            var currCard = CardFileInfo(element.path.toString().trim());
            cardInfoList.add(currCard);
          }
        }); //end of foreEach
        return cardInfoList;
      }); //end of files.then
    }); //end of dirName.then
  } //end of getFileList()

当我单步执行代码时,"return Text("Still looking");"行最多执行两次。

函数最终返回值,但看起来 FutureBuilder 没有等待足够长的时间来返回值。

我是 Flutter 和 Dart 的新手,这个问题真的让我很困惑。

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    您对问题所在位置的直觉是正确的;它发生在.then 电话中。发生这种情况的原因是因为.then 立即返回(它是“非阻塞的”),因此该方法将立即返回。 Future 将在没有附加值的情况下完成,因为 .then 调用不会完成。在未来的某个时候,应该填充列表,但您将不知道何时使用当前方法。

    我能想到三种解决方案来解决这个问题:

    1. (我会推荐这种方法)使用async/await 关键字使您的方法更容易异步。我不能保证它会按原样工作(自从我处理 Dart/Flutter 以来已经有几个月了),所以一些语法可能不正确,但想法就在那里。
     Future<List<CardFileInfo>> getFileList() async {
        List<CardFileInfo> cardInfoList = [];
        final dirName = await getApplicationDocumentsDirectory();
    
        final files = await dirName.list().toList();
        for (final element in files) {
          final type = element.path.toString().split(".").last.trim();
          if (type == "tsv") {
            final currCard = CardFileInfo(element.path.toString().trim());
            cardInfoList.add(currCard);
          }
        }
    
        return cardInfoList;
      } //end of getFileList()
    
    1. 使用Completer。这为您提供了更多控制权,但在这种情况下我不建议您这样做,因为它需要样板文件并且会损害此处的可读性。
    2. 在将填充列表的StatefulWidgetinitState 中分派一个调用,然后在提取完成后使用setState 调用来更新用户界面。

    【讨论】:

      【解决方案2】:

      FutureBuilder 不起作用,因为localFileHelper.getFileList 是异步的但不返回Future,因此_getFileList(最终是FutureBuilder)无法等待它完全的。另外:

        List<CardFileInfo> getFileList() {
      
          List<CardFileInfo> cardInfoList = [];
          ...
          dirName.then((dir) {
            final files = dir.list().toList();
            files.then((values) {
              ...
              return cardInfoList; // <-- This doesn't do what you think it does.
            }); //end of files.then
          }); //end of dirName.then
        } //end of getFileList()
      

      您打算让return cardInfoList; 语句从您的localFileHelper.getFileList() 方法返回一个值,但它没有:它从您传递给Future.then回调 返回一个值。 localFileHelper.getFileList() 而是立即返回。如果没有显式的 return 语句,它将返回 null。 (如果你运行dartanalyzer,它应该会生成一个警告。)

      Future.then 本身返回一个Future,它将具有执行其回调的结果。但是,您丢弃了Future.then 的返回值,最终丢失了返回值并失去了调用者等待回调执行的机会。

      Gregory Conrad's answer 中所述,使用async/await 代替Future.then 会大大简化您的代码并避免您所犯的错误。此外,我建议在您的analysis_options.yaml 文件中启用unawaited_futures lint,以便将来检测此类错误。

      【讨论】:

      • 好收获!在写我的答案时,我完全掩盖了这些。
      猜你喜欢
      • 1970-01-01
      • 2022-07-24
      • 1970-01-01
      • 1970-01-01
      • 2012-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-05
      相关资源
      最近更新 更多