3

Because my flutter app was not running fluently, I have figured that the problem might be the single-threading in flutter. So I am taking my first steps in running isolates to avoid only one event loop. However I faced the following issue which is probably wrong use of isolate:

I am calling method addNewChild from outside the class. I am converting all the variables to a map to run compute method and call addNewChildStatic method which is static, like this:

    void addNewChild(
    childFacilityId,
    childFacility,
    childGroup,
    groupId,
    childFirstName,
    childLastName,
    userImageFile,
    isHorizontalImage,
  ) {
    Map map = Map();
    map['childFacilityId'] = childFacilityId;
    map['childFacility'] = childFacility;
    map['childGroup'] = childGroup;
    map['groupId'] = groupId;
    map['childFirstName'] = childFirstName;
    map['childLastName'] = childLastName;
    map['userImageFile'] = userImageFile;
    map['isHorizontalImage'] = isHorizontalImage;


    compute(addNewChildStatic, map); //here I run isolate using compute method
  }

addNewChildStatic looks like this:

static Future<void> addNewChildStatic(Map map) async {
    print('COMPUTE addNewChildStatic STARTED');
    WidgetsFlutterBinding.ensureInitialized(); // I have added this because the errors I was getting in the console
    Firebase.initializeApp(); // I have added this because the errors I was getting in the console that there was no Firebase

    final childFacilityId = map['childFacilityId'];
    final childFacility = map['childFacility'];
    final childGroup = map['childGroup'];
    final childGroupId = map['groupId'];
    final childFirstName = map['childFirstName'];
    final childLastName = map['childLastName'];
    final childImageFile = map['userImageFile'];
    final isHorizontalImage = map['isHorizontalImage'];

try{
//methods
} catch(e){
//error handling
}
    }

The thing is I am getting the following error:

flutter: COMPUTE addNewChildStatic STARTED
[VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: UI actions are only available on root isolate.
#0      PlatformDispatcher._nativeSetNeedsReportTimings (dart:ui/platform_dispatcher.dart:501:59)
#1      PlatformDispatcher.onReportTimings= (dart:ui/platform_dispatcher.dart:493:29)
#2      SchedulerBinding.addTimingsCallback (package:flutter/src/scheduler/binding.dart:279:26)
#3      SchedulerBinding.initInstances (package:flutter/src/scheduler/binding.dart:211:7)
#4      ServicesBinding.initInstances (package:flutter/src/services/binding.dart:36:11)
#5      PaintingBinding.initInstances (package:flutter/src/painting/binding.dart:20:11)
#6      SemanticsBinding.initInstances (package:flutter/src/semantics/binding.dart:18:11)
#7      RendererBinding.initInstances (package:flutter/src/rendering/binding.dart:28:11)
#8      WidgetsBinding.initInstances (package:flutter/src/widgets/binding.dart:245:11)
#9      new BindingBase (package:flutter/src/foundation/binding.dart:147:5)
#10     new _Widgets<…>

I have figured that it has something to do that the UI is updated in the main thread only so I should do some communication between isolates. Unfortunately I have no idea how to approach it. I would appreciate any help guys.

Huge thanks in advance!

1 Answer 1

3

As you have correctly mentioned, you can run UI updates only on the main thread and not on any other isolates that you create via compute().

So first thing you have to do is to remove

WidgetsFlutterBinding.ensureInitialized();

Then, for simple communication with the isolate, you can also return values and use them inside a FutureBuilder for example.

static Future<string> addNewChildStatic(Map map) async {
    // Perform some heavy async computation tasks
    // Return a result object in the end (in this case, a string).
    return "Finished calculation"
}

to be consumed via

FutureBuilder(
    future: compute(_runningFunction, 10),
    builder: (context, snapshot) {
        if (snapshot.hasData) {
            return Text(snapshot.data);
        } else {
            return CircularProgressIndicator();
        }
  },
),

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

5 Comments

Hey, thanks for your help. To be clear you mean to use (as in above example) addNewChildStatic in FutureBuilder’s future, using compute, so like this; future: compute(addNewFhildStatic, map)?
I understand this approach, however the code in my methods deos only writing some values to Firebase Firestore. There are no variables or methods that directly update UI - those are somewhere else using StreamBuilders but those are not related to this function.
It is this method that is interacting with UI: WidgetsFlutterBinding.ensureInitialized
I have tried FutureBuilder but received this: The "instance" getter on the ServicesBinding binding mixin is only available once that binding has been initialized. Typically, this is done by calling "WidgetsFlutterBinding.ensureInitialized()" or "runApp()" (the latter calls the former). Typically this call is done in the "void main()" method. The "ensureInitialized" method is idempotent; calling it multiple times is not harmful. After calling that method, the "instance" getter will return the binding.
And this time, adding WidgetsFlutterBinding.ensureInitialized() doesn't help at all no matter if I add it build method or just the method being computed.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.