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

huangapple go评论100阅读模式
英文:

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

问题

在我的Flutter应用程序上运行Android API28模拟器时,启动Isolate会导致应用程序崩溃并显示以下错误:

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

我已经在runApp(const MyApp());之前运行了WidgetsFlutterBinding.ensureInitialized();,这应该确保在应用程序开始运行之前BackgroundIsolateBinaryMessenger已经初始化。

是否仍然需要运行BackgroundIsolateBinaryMessenger.ensureInitialized,以及如何执行此操作?

英文:

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

答案1

得分: 4

将令牌传递给孤立体。

顶级函数:

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

要使用它:

var contacts = await computeIsolate(_getContacts);

// 确保静态函数在类内部
static Future<List<Contact>> _getContacts() async {
  final contacts = await FlutterContacts.getContacts(withProperties: true);
  return contacts;
}
英文:

Pass the token to the isolate.

Top-level function:

Future&lt;dynamic&gt; computeIsolate(Future Function() function) async {
final receivePort = ReceivePort();
var rootToken = RootIsolateToken.instance!;
await Isolate.spawn&lt;_IsolateData&gt;(
_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&lt;List&lt;Contact&gt;&gt; _getContacts() async {
final contacts = await FlutterContacts.getContacts(withProperties: true);
return contacts;
}

答案2

得分: 2

在隔离的顶部添加 BackgroundIsolateBinaryMessenger.ensureInitialized

RootIsolateToken rootIsolateToken = RootIsolateToken.instance!;

void _isolateTask(SendPort sendPort) async {
    debugPrint("Inside _isolateTask");
    BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);
    accelerometerEvents.listen((AccelerometerEvent event) {
      debugPrint('_isolateTask x: $event.x');
      sendPort.send(event.x);
    });
}
英文:

Add BackgroundIsolateBinaryMessenger.ensureInitialized at top of isolate.

RootIsolateToken rootIsolateToken = RootIsolateToken.instance!;
void _isolateTask(SendPort sendPort) async {
debugPrint(&quot;Inside _isolateTask&quot;);
BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);
accelerometerEvents.listen((AccelerometerEvent event) {
debugPrint(&#39;_isolateTask x: $event.x&#39;);
sendPort.send(event.x);
});
}

答案3

得分: 0

在我的情况下,我是在按钮中调用compute,所以我只需要在按钮中添加获取RootIsolate实例的调用。

GestureDetector(
 onTap: () async {
   final token = RootIsolateToken.instance;
   final result = await compute(functionName, token);
  }
}

dynamic functionName(dynamic token){
  BackgroundIsolateBinaryMessenger.ensureInitialized(token);
  //代码的其余部分。
}
英文:

In my case i was calling the compute in a button so all i had to do was put the call to get the instance of the RootIsolate in the button

GestureDetector(
onTap: () {
final token = RootIsolateToken.instance;
final result = await compute(functionName,token);
}
}
dynamic functionName(dynamic token){
BackgroundIsolateBinaryMessenger.ensureInitialized(token);
//Rest of code.
}

huangapple
  • 本文由 发表于 2023年4月6日 21:29:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/75950122.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定