FutureBuilder makes my app freeze because it waits for a file to load before building

喜夏-厌秋 提交于 2020-03-02 17:13:08

问题


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.

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();
                    }
                  },

                )

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?


回答1:


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.

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.

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>);

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

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.




回答2:


I think the problem is here:

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

The ConnectionState.done is set just after the stream is connected (I assume you're using a stream) so that condition is always true. I think is better if you use the snapshot.hasData as validation like so:

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


来源:https://stackoverflow.com/questions/56484082/futurebuilder-makes-my-app-freeze-because-it-waits-for-a-file-to-load-before-bui

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!