7

I'm working on an app that captures and processes an image. A simplified version of the code is:

build() {
   return FloatingActionButton(
        onPressed: processImage,
        child: Icon(
          Icons.camera_alt,
          color: color,
        ),
      ); 
}

processImage(Camera image) async {
   await image.process();   
}

And in another class:

Future<image> process() {
  return Future(() {
    for (int x = 0; x < width; x++) {
      for (int y = 0; y < height; y++) {
        //process image
      }
    }
  });
}

But when process() is running, the UI freezes.

Why is this happening? Isn't that function passed to Future constructor running in the background?

10
  • 1
    I'm not 100% sure, but I do know dart uses an event loop and everything will run on the main thread (just perhaps at some point in the future, in the case of asynchronous code). As such, that code will eventually be executed on the main thread, causing a block. Consider using Dart's isolates; that should fix the issue. Flutter has a built-in convenience method to do this for you, but I can't remember what it is called off the top of my head. Commented Oct 25, 2020 at 3:21
  • 2
    I believe I found it: api.flutter.dev/flutter/foundation/compute.html Commented Oct 25, 2020 at 3:27
  • 1
    @GregoryConrad Thank you, that worked for me, is not a very elegant solution, but it works, if you want to make it an answer, I'll be happy to make it as the right answer Commented Oct 25, 2020 at 4:25
  • 1
    what is not "elegant" in compute() function? Commented Oct 25, 2020 at 4:31
  • 2
    @pskink My function receives 6 parameters, and you cannot call a class method: "The callback argument must be a top-level function, not a closure or an instance or static method of a class", and you can only pass one parameter, so I had to convert all my params to a Map<String, dynamic>, create a top-level function that receives the map, and destructure to original variables. Commented Oct 25, 2020 at 4:35

2 Answers 2

8

As Dart uses an event loop, all code (synchronous and asynchronous) will simply be run on the same isolate (think thread in other languages as an analogy), just at different points in time. As such, when your process method is dequeued and executed, it will block the thread and cause frames to be dropped due to a longer execution time, despite being asynchronous. The optimal solution to the problem is to spawn another isolate in a new thread, and carry out the computation there. Flutter provides a convenience method for this exact use case, called compute. It takes a top-level function (not in a class, nor anonymous) that can have a primitive type parameter (including Map and List) as an argument and will return at some point in the future. For more information on compute, see its documentation linked above.

If you have multiple parameters that you need to pass to compute, a common pattern (outside of just this use case) is making a method that serializes a class' fields to a Map<String, dynamic>, and a factory constructor that creates an object from a Map<String, dynamic>. This process would be easier with reflection, but Flutter disables it due to performance reasons.

For a full example on compute from the Flutter documentation, see here: https://flutter.dev/docs/cookbook/networking/background-parsing

Sign up to request clarification or add additional context in comments.

Comments

-1

You can insert the gap into the event loop.
Simple way:

Future<image> process2() {
  return Future(() async {
    for (var x = 0; x < width; x++) {
      for (var y = 0; y < height; y++) {        
        // process       
      }

      if (x % 100 == 0) {
        await Future.delayed(Duration(seconds: 100));
      }
    }
  });
}

2 Comments

Wrong answer, this will not help. UI still freezes.
I found this article talking about using event loop to handle heavy tasks. I don't know if the same method can be used for this case (processing image). https://hackernoon.com/executing-heavy-tasks-without-blocking-the-main-thread-on-flutter-6mx31lh

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.