Flutter - How do I compute a heavy task that includes a future without blocking the UI?
Asked Answered
S

1

11

I'm creating an app that fetches posts from the internet as json. I parse the json into Post objects in flutter using a factory. A Post object includes a title, body and image. I display these posts in a listview with a listview builder. The heavy task is that I calculate 2 dominant colors from the image to set as the background gradient of a post item. For this I use: https://pub.dartlang.org/packages/palette_generator

I calculate the 2 dominant colors in the json parser factory because then I have a complete Post object with al the needed information. Also this way I don't have to calculate the colors when rendering an Post object. I do this with the following code:

Future<List> _getColors() async {
  Color gradientOne, gradientTwo;
  String imageUrl = json['image'];

  paletteGenerator = await PaletteGenerator.fromImageProvider(
      CachedNetworkImageProvider(imageUrl));

  gradientOne = paletteGenerator.colors.toList()[0];
  gradientTwo = paletteGenerator.colors.toList()[1];

  return [gradientOne, gradientTwo];
}

I add this to the Post object and in the render I wait on this future:

post.gradientColors
    .then((result) => {
          gradient = result,
          this.setState(() {
                  loading = false;
                })
        })

In the main UI I show a loading indicator until all the futures are resolved. For this I use the following code:

List<Future> futures = [];

  for (var post in tmpList) {
    futures.add(post.gradientColors);
  }
  await Future.wait(futures)
      .then((result) => {list.addAll(tmpList)});
}

This works ok except for the laggy UI when fetching new posts. After a bit of reading I found that I can use Isolates in Flutter. So I changed my parsing function as described here: https://flutter.io/docs/cookbook/networking/background-parsing

This works flawlessly and my app is running without any lag, the drawback is that my colors aren't calculated. For some reason when I use compute() my Future never comes to a result.

Is it possible to use compute in this situation or is there a better way to calculate the colors without causing lag in my UI?

EDIT

I tried programming an Isolate without compute, but the color futures still don't load. This is the code I used:

ReceivePort receivePort = ReceivePort();
Isolate isolate = await Isolate.spawn(getMorePosts, receivePort.sendPort);
receivePort.listen((data) {
  list.addAll(data);
});

I do receive all the data but again my futures don't finish.

Staciastacie answered 17/2, 2019 at 17:17 Comment(0)
N
4

Unfortunately compute() only supports sync results.

compute() is simple and is just a wrapper to make it easier to start up isolates.

You can just start an additional isolate using custom code and gain more power.

https://api.dartlang.org/stable/2.1.1/dart-isolate/dart-isolate-library.html

The isolate package provides some convenience features to make it easier to work with isolates.

Nonrepresentational answered 17/2, 2019 at 17:31 Comment(2)
I tried using Isolate without compute, see my edit. Do you know if there is an other way to program isolates in which I can use futures?Staciastacie
What about isolates in flutter web? Is there any alternative?Alvy

© 2022 - 2024 — McMap. All rights reserved.