为什么这个未来永远无法完成?

时间:2020-06-21 11:11:33

标签: android flutter dart

我有以下代码:

class FileData {
  Future<String> get _localPath async {
    print('D: Local'); //D
    final directory = await getApplicationDocumentsDirectory();
    print('D: Directory: $directory'); //D
    return directory.path;
  }

  Future<File> get _localFile async {
    final path = await _localPath;
    print('D: Path: $path'); //D
    return File('$path/file.dat');
  }
  
  Future<File> _future;
  Future<RandomAccessFile> _futureRandomAccessFile;
  File _file;
  RandomAccessFile _randomAccessFile;

  FileData() {
    print('D: First'); //D
    _future = _localFile;
    _future = _future.then(
      (File file) {
        print('D: Stuff'); //D
        if(file == null) throw 'file == null';
        _file = file;
        print('D: Foo'); //D
        _futureRandomAccessFile = file.open(mode: FileMode.append);
        _futureRandomAccessFile = _futureRandomAccessFile.then(
          (RandomAccessFile randomAccessFile) {
            if(randomAccessFile == null) throw 'randomAccessFile == null';
            _randomAccessFile = randomAccessFile;

            print('D: Position: ${_randomAccessFile.positionSync()}'); //D
            int byte = DateTime.now().second; //D
            print('D: Write: $byte'); //D
            _randomAccessFile.writeByte(byte); //D

            return randomAccessFile;
          },
          onError: (e) {
            throw e;
          }
        ).timeout(Duration(seconds: 2));
        return file;
      },
      onError: (e) {
        print('D: Bad'); //D
        throw e;
      }
    ).timeout(Duration(seconds: 2));
  }

  _syncRandomAccessFile() {
    while(_randomAccessFile == null) {
      print('Waiting on _randomAccessFile...');
    }
  }

  void close() {
    _syncRandomAccessFile();

    print('D: Position: ${_randomAccessFile.positionSync()}'); //D
    _randomAccessFile.setPositionSync(0); //D
    print('D: Position: ${_randomAccessFile.positionSync()}'); //D
    print('D: Byte: ${_randomAccessFile.readByteSync()}'); //D
    int byte = DateTime.now().second; //D
    print('D: Write: $byte'); //D
    _randomAccessFile.writeByte(byte); //D

    _randomAccessFile.close();
    _randomAccessFile = null;
  }
}

FileData fileData;

这在我的应用首页状态:

@override
  void initState() {
    super.initState();
    fileData = FileData();
    sleep(Duration(seconds: 1));
    fileData.close();
  }

我希望发生以下事件:

D: First
D: Local
(some or none) Waiting on _randomAccessFile...
D: Directory: <whatever>
D: Path: <whatever>
D: Stuff
D: Foo
(some or none) Waiting on _randomAccessFile...
D: Position: <whatever>
D: Write: <whatever>
D: Position: <whatever>
D: Position: 0
D: Byte: <whatever>
D: Write: <whatever>

相反,我得到了:

D: First
D: Local
(a lot of) Waiting on _randomAccessFile...
(app freezes)

我不明白为什么会这样。我显然需要在读取/写入/关闭文件之前将其打开,并且我需要在一个实例变量中使其能够在同步和异步代码中使用。我的理解是,getApplicationDocumentsDirectory()返回的未来由于某种原因永远不会完成。

我希望这是我所遇到的一些基本误会,比其他任何事情都重要。

2 个答案:

答案 0 :(得分:1)

您的sleep调用不符合您的期望,因为它不允许运行异步操作。

按持续时间指定的持续时间进行睡眠。

请谨慎使用此选项,因为在睡眠调用中阻塞异步操作后,无法单独处理任何异步操作。

https://api.flutter.dev/flutter/dart-io/sleep.html

此外,在构造函数内部进行异步操作也不是一个好主意,因为您无法确定何时完全创建对象。相反,请在FileData内创建一个静态方法,该方法可以返回Future<FileData>,目的是在返回完全构造的对象之前执行所有异步操作。这样,您无需sleep

答案 1 :(得分:0)

julemand101的评论给出了这个问题的答案。万一有人发现这个问题,并正在寻找我从中学到的详细解释...

Dart是单线程的。仅当当前操作完成并且控制返回到事件循环时,异步操作才完成。 await以某种方式确保发生这种情况。如果我将fileData.close()放在事件循环调用的另一个函数中,也会发生这种情况。但是我打电话给构造函数,然后等待将来完成,而又没有将控制权交还给它们之间的事件循环,所以将来永远不会完成,并且永远锁定着。