Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter Isolates: The BackgroundIsolateBinaryMessenger.instance value is invalid until BackgroundIsolateBinaryMessenger.ensureInitialized is executed

On my Flutter app running on a Android API28 emulator, starting an Isolate will cause the app to crash with the error:

[Bad state: The BackgroundIsolateBinaryMessenger.instance value is invalid until BackgroundIsolateBinaryMessenger.ensureInitialized is executed., #0 BackgroundIsolateBinaryMessenger.instance

Am already running WidgetsFlutterBinding.ensureInitialized(); before runApp(const MyApp());, which should ensure that BackgroundIsolateBinaryMessenger is already initialized before the app starts running.

Do we still have to run BackgroundIsolateBinaryMessenger.ensureInitialized, and how do we do this?

import 'dart:isolate';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:sensors_plus/sensors_plus.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  double _x = 0;

  static void _isolateTask(SendPort sendPort) async {
    debugPrint("Inside _isolateTask");

    accelerometerEvents.listen((AccelerometerEvent event) {
      debugPrint('_isolateTask x: $event.x');
      sendPort.send(event.x);
    });
  }

  void _startIsolate() async {
    debugPrint("_startIsolate()");

    var receivePort = ReceivePort();

    await Isolate.spawn(_isolateTask, receivePort.sendPort);

    receivePort.listen((dynamic message) {
      setState(() {
        _x = message;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'X: $_x',
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _startIsolate,
        tooltip: 'Start Isolate',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

Full Trace

I/flutter ( 5071): _startIsolate()
I/flutter ( 5071): Inside _isolateTask
I/flutter ( 5071): error: [Bad state: The BackgroundIsolateBinaryMessenger.instance value is invalid until BackgroundIsolateBinaryMessenger.ensureInitialized is executed., #0      BackgroundIsolateBinaryMessenger.instance
_background_isolate_binary_messenger_io.dart:27
I/flutter ( 5071): #1      _findBinaryMessenger
platform_channel.dart:135
I/flutter ( 5071): #2      EventChannel.binaryMessenger
platform_channel.dart:629
I/flutter ( 5071): #3      EventChannel.receiveBroadcastStream.<anonymous closure>
platform_channel.dart:649
I/flutter ( 5071): #4      _runGuarded (dart:async/stream_controller.dart:814:24)
I/flutter ( 5071): #5      _BroadcastStreamController._subscribe (dart:async/broadcast_stream_controller.dart:207:7)
I/flutter ( 5071): #6      _ControllerStream._createSubscription (dart:async/stream_controller.dart:827:19)
I/flutter ( 5071): #7      _StreamImpl.listen (dart:async/stream_impl.dart:471:9)
I/flutter ( 5071): #8      new _ForwardingStreamSubscription (dart:async/stream_pipe.dart:114:10)
I/flutter ( 5071): #9      _ForwardingStream._createSubscription (dart:async/stream_pipe.dart:86:16)
I/flutter ( 5071): #10     _ForwardingStream.listen (dart:async/stream_pipe.dart:81:12)
I/flutter ( 5071): #11     _MyHomePageState._isolateTask
main.dart:44
I/flutter ( 5071): #12     _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:300:17)
I/flutter ( 5071): #13     _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:192:26)
I/flutter ( 5071): ]

Dependencies

dependencies:
    flutter:
      sdk: flutter
    wear: ^1.1.0
    sensors_plus: ^2.0.2
like image 207
gameveloster Avatar asked Nov 28 '25 01:11

gameveloster


1 Answers

Pass the token to the isolate.

Top-level function:

Future<dynamic> computeIsolate(Future Function() function) async {
  final receivePort = ReceivePort();
  var rootToken = RootIsolateToken.instance!;
  await Isolate.spawn<_IsolateData>(
    _isolateEntry,
    _IsolateData(
      token: rootToken,
      function: function,
      answerPort: receivePort.sendPort,
    ),
  );
  return await receivePort.first;
}

void _isolateEntry(_IsolateData isolateData) async {
  BackgroundIsolateBinaryMessenger.ensureInitialized(isolateData.token);
  final answer = await isolateData.function();
  isolateData.answerPort.send(answer);
}

class _IsolateData {
  final RootIsolateToken token;
  final Function function;
  final SendPort answerPort;

  _IsolateData({
    required this.token,
    required this.function,
    required this.answerPort,
  });
}

To use it:

var contacts = await computeIsolate(_getContacts);

// Make sure static function if inside class
static Future<List<Contact>> _getContacts() async {
  final contacts = await FlutterContacts.getContacts(withProperties: true);
  return contacts;
}
like image 86
Kucing Malaya Avatar answered Nov 30 '25 16:11

Kucing Malaya



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!