Flutter:未处理的异常:在绑定初始化之前访问了ServicesBinding.defaultBinaryMessenger。

275

有什么解决这个问题的方案吗?

堆栈跟踪:

[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: ServicesBinding.defaultBinaryMessenger was accessed before the binding was initialized.
If you're running an application and need to access the binary messenger before `runApp()` has been called (for example, during plugin initialization), then you need to explicitly call the `WidgetsFlutterBinding.ensureInitialized()` first.
If you're running a test, you can call the `TestWidgetsFlutterBinding.ensureInitialized()` as the first line in your test's `main()` method to initialize the binding.
#0      defaultBinaryMessenger.<anonymous closure> (package:flutter/src/services/binary_messenger.dart:73:7)
#1      defaultBinaryMessenger (package:flutter/src/services/binary_messenger.dart:86:4)
#2      MethodChannel.binaryMessenger (package:flutter/src/services/platform_channel.dart:140:62)
#3      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:314:35)
<asynchronous suspension>
#4      MethodChannel.invokeMapMethod (package:f<…>

1
请在main()函数中将以下代码行作为第一条语句 - WidgetsFlutterBinding.ensureInitialized(); - Vijay Ram
13个回答

592
这个问题出现在您升级Flutter时。原因是您正在等待一些数据或在main()函数内运行async函数。我曾在main()函数内初始化ScopedModel并等待某些数据。有一个非常简单的解决方法。只需在void main()中运行WidgetsFlutterBinding.ensureInitialized(),然后再运行runApp()。非常有效!
void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(Delta(
    model: ProductDataModel(),
  ));
}

51
确保WidgetFlutterBinding.ensureInitialized()是main()函数的第一行。然后按照通常的方法继续操作。 - Avnish Nishad
20
这样做可能会有什么潜在的负面影响?所有Flutter应用程序都应该在main()方法开头加上那行代码吗? - user482594
4
如果您在main()函数中使用异步方法,您需要添加这个。 - Debasmita Sarkar
3
无法在v1.14.4/v1.14.6上工作,会在变量databasesPath = await getDatabasesPath();处中断。 - Ares91
非常感谢,这对我很有效,但是为什么我们必须将widgetFlutterBinding放在主函数的顶部?这只是针对主函数还是任何其他未来函数都可能存在相同的问题? - Salah dine Maham
显示剩余3条评论

106

如果您正在等待main()方法运行,通常会出现这种情况。所以解决方案是:

void main() {
  // add this, and it should be the first line in main method
  WidgetsFlutterBinding.ensureInitialized(); 

  // rest of your app code
  runApp(
    MaterialApp(...),
  );
}

2
无法工作 - 在 join(await getDatabasesPath(), 'mydb.db') 处中断。 - live-love

38

我不确定我的回答是否正确,但在最近的Flutter升级后我遇到了同样的错误,找到并解决了这个问题,现在分享我的发现。

看起来这个错误可能是由于最近的一个重大更改引起的: https://groups.google.com/forum/#!msg/flutter-announce/sHAL2fBtJ1Y/mGjrKH3dEwAJ

因此,我们需要手动更改代码如下:

  • 如果您正在运行应用程序并需要在调用runApp()之前访问二进制信使(例如在插件初始化期间),则需要显式调用 WidgetsFlutterBinding.ensureInitialized()
  • 如果您正在运行测试,则可以在您的测试的main()方法中首先调用TestWidgetsFlutterBinding.ensureInitialized()来初始化绑定。

或者,如果您像我一样是新手,难以理解上面和#38464,您可以通过切换到beta频道来暂时避免此问题。只需运行“flutter channel beta”。重大更改尚未在beta频道中实现,因此切换到beta频道后,您至少在短期内不会遇到此错误。


18

只需将此行添加到main.dart中

WidgetsFlutterBinding.ensureInitialized(); 

你的代码看起来像这样

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  return runApp(MultiProvider(
    providers: [
      ChangeNotifierProvider.value(
        value: AppState(),
      )
    ],
    child: MyApp(),
  ));
}

13
如果您尝试在隔离环境中执行插件本地代码,则可能会遇到此问题。这里的isolate_handler文档解释得很好

插件使用称为平台通道的机制在Dart和原生端之间进行通信,使用MethodChannel类型的消息传递机制。该机制依赖于底层UI引擎的元素才能工作。

问题在于,隔离只会在需要处理计算密集型的Dart代码的情况下提供性能提升。插件的平台代码将再次使用主(UI)线程。
在隔离环境中调用WidgetsFlutterBinding.ensureInitialized也会因隔离中缺少底层UI引擎而失败。

解决方法是使用 isolate_handlerflutter_isolate 来生成隔离体。 - jon
1
@jon:这就是isolate_handler文档所说的:“如果你的任务在Dart端计算密集,使用isolate会有很大帮助。如果时间花费在插件本地端,除非你在插件本身上创建自己的本地线程,否则你不会获得太多好处。在你的主要Dart应用程序中无法做任何事情。”因此,除非插件本身被设计为使用多个线程,否则这里没有任何解决方法。 - sjsam
@letiagoalves 从上面的文档中可以看出,这里没有任何变通方法。如果您设计一个插件,请确保它是多线程的。 - sjsam

8
void main()中添加这行代码,错误将被解决。
WidgetsFlutterBinding.ensureInitialized();

7

解决方案:在调用异步函数之前,先调用WidgetsFlutterBinding.ensureInitialized();


void main() async {
  WidgetsFlutterBinding.ensureInitialized();   //  ADD THIS BEFORE YOUR ASYNC FUNCTION CALL.
  await Firestore.instance.settings(...);      //  NOW YOU CAN CALL ASYNC FUNCTION.   
  ...
  runApp(
    ...
  )

6
这可以通过使用 WidgetsBinding.ensureInitialized() 来解决,该方法建立了 Dart LayerPlatform 之间的通信。
如果需要在调用 [runApp] 之前初始化绑定,我们需要调用此方法。在建立绑定之前,Flutter 无法直接与Flutter引擎交互。
void main() async {
  WidgetsFlutterBinding.ensureInitialized();   
  /// Your Code which required binding
  runApp(
    ...
  )
}
WidgetsFlutterBinding.ensureInitialized() 支持多种绑定,例如:
  1. ServicesBinding 用于监听平台消息并将其指向传入消息的处理程序(BinaryMessenger)。
  2. PaintingBinding 负责与绘图库进行绑定。
  3. RenderBinding 将渲染树绑定到Flutter引擎。
  4. WidgetBinding 将小部件树绑定到Flutter引擎。
  5. SchedulerBinding 是立即执行任务的调度程序。
  6. SemanticsBinding 将语义层和Flutter引擎绑定在一起。
  7. GestureBinding 是手势子系统的绑定。
所有这些绑定都将作为Dart和Platform之间的粘合剂。

6
在我的情况下,使用方向时,

解决之前:

void main() {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_).{
runApp(MyApp());
});
}

解决方法使用:
void main() {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
  .then((_) {
runApp(MyApp());
});
}

重点是在主类的第一行添加WidgetsFlutterBinding.ensureInitialized()


4

值得注意的是,如果您从独立体中收到此错误,则接受的解决方案将不起作用。

WidgetsFlutterBinding.ensureInitialized();

只能在主线程上绑定,不能在其他线程上绑定。目前正在努力解决这个限制,您可以在此处关注该问题的进展:

https://github.com/flutter/flutter/issues/13937


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接