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

问题描述:

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

I am writing a very basic flutter app for reading public domain books. I included a .txt file containing a book in my app's assets. since a book is quite long and would take time to load I was trying to use a FutureBuilder that will display a circular progress indicator while the book is loading, however, when I click on the button to open the book the app freezes until the book is loaded instead of transitioning to the book page and showing a progress indicator while the book is loading as I would like.

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

I checked this for a smaller file and it didn't freeze. I tried to just tell the FutureBuilder to show the progress indicator and again, it didn't freeze.

FutureBuilder(
                  future: text, //Future<String>
                  builder: (context,snapshot) {
                    if (snapshot.connectionState==ConnectionState.done) {
                      return Text(
                        snapshot.data,
                        style: TextStyle(fontSize: 20),);
                    }
                    else {
                      return CircularProgressIndicator();
                    }
                  },

                )

看起来FutureBuilder只是尝试使用文本进行构建,而不是不使用文本进行构建并稍后添加像它应该做的那样。

It looks like the FutureBuilder is just trying to build with the text instead of building without it and adding it later like it is supposed to do. How do I tell it to do that?

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

Dart is mostly single-threaded. So when you're reading the text, it's doing it in the same thread as the UI and that's why it's slowing it down. Using a future means that the call may be delegated to a later time (depending on how you schedule it), but it is still running in the same thread.

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

What you want to do is use an Isolate, and do the file reading within that. Once you have the file (and do any processing you need to do), you should be able to pass it back to the Text class and it should be faster - although if you're dealing with a very large amount of text it may still stutter a bit as the Text class still has to process all the text. If it does stutter, I'd recommend breaking the text into parts (chapter/paragraph?) and using multiple text and/or richtext objects to display it in a list.

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

The easiest way to use an Isolate in flutter is the `compute' function.

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

Then your future will have something like this in it:

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

请注意,的输入和输出计算有一些限制,因为它在后台使用了隔离的SendPort

Note that the input and output of compute have some limitations since it uses an Isolate's SendPort under the hood:


消息的内容可以是:原始值(null,num,bool,double,String),SendPort实例和列表以及其元素是其中任何一个的地图。列表和地图也可以循环。

The content of message can be: primitive values (null, num, bool, double, String), instances of SendPort, and lists and maps whose elements are any of these. List and maps are also allowed to be cyclic.