FutureBuilder使我的应用程序冻结,因为它在构建之前会等待文件加载

时间:2019-06-06 19:38:51

标签: flutter dart future

我正在编写一个非常基本的flutter应用程序,用于阅读公共领域的书籍。我在应用程序的资产中包含一个.txt文件,其中包含一本书。由于一本书很长,并且需要花费一些时间来加载,因此我尝试使用FutureBuilder,它会在加载该书时显示一个圆形的进度指示器,但是,当我单击按钮以打开该书时,应用会冻结直到该书加载,而不是过渡到书籍页面,并在加载书籍时显示进度指示器。

我检查了一个较小的文件,但没有冻结。我试着只是告诉FutureBuilder显示进度指示器,但它并没有冻结。

<TextField label="Date:" disabled styles={{ root: { width: 300 } }} defaultValue="Wednesday, May 8, 2019" />
<TextField label="Date2:" disabled styles={{ root: { width: 300 } }} defaultValue="Wednesday, May 9, 2019" />
<TextField label="Date3:" disabled styles={{ root: { width: 300 } }} defaultValue="Wednesday, May 10, 2019" />

看起来FutureBuilder只是尝试使用文本进行构建,而不是不使用文本进行构建,然后像预期的那样添加它。我如何告诉它做到这一点?

2 个答案:

答案 0 :(得分:1)

Dart大多是单线程的。因此,当您阅读文本时,它是在与UI相同的线程中执行的,这就是它使速度变慢的原因。使用Future意味着可以将呼叫委派到以后的时间(取决于您如何安排它),但是它仍在同一线程中运行。

您要使用的是Isolate,然后在其中读取文件。拥有文件(并执行所需的任何处理)后,您应该能够将其传递回Text类,并且速度应该更快-尽管如果要处理大量文本,它可能仍然由于Text类仍必须处理所有文本,因此有点口吃。如果确实出现断断续续的情况,我建议将文本分成多个部分(章节/段落?),并使用多个文本和/或RTF对象将其显示在列表中。

在抖动中使用隔离的最简单方法是`compute' function

那么您的未来将拥有这样的东西:

await compute(readFile, <path to file>);

请注意,compute的输入和输出有一些限制,因为它在后台使用了Isolate's SendPort

  

消息的内容可以是:原始值(null,num,bool,double,String),SendPort的实例以及其元素为这些元素的列表和映射。列表和地图也可以循环。

答案 1 :(得分:0)

我认为问题出在这里

if (snapshot.connectionState == ConnectionState.done) {
  return Text(snapshot.data, style: TextStyle(fontSize: 20));
}

在连接流之后立即设置ConnectionState.done(我假设您正在使用流),因此该条件始终为true。 我认为,如果您使用snapshot.hasData这样的验证方式更好:

FutureBuilder<String>(
    future: futureStream,
    builder: (context, snapshot) {
      if (snapshot.hasData) {
        return Text(snapshot.data);
      } else {
        return CircularProgressIndicator();
      }
    },
);