ensureInitialized的作用
在 Flutter 里 WidgetsFlutterBinding.ensureInitialized(); 主要作用是**确保 Flutter 的引擎和框架层已经完成绑定和初始化**,通常在 main() 函数中调用。
Flutter 程序启动时,会创建一个 Binding(绑定类),用来把 Flutter 引擎 (engine) 和 Flutter 框架 (framework) 连接起来。
WidgetsBinding:负责调度、手势、渲染、widget 生命周期等。WidgetsFlutterBinding:在WidgetsBinding的基础上,把所有和 Flutter App 运行相关的 Binding 组合起来(渲染、手势、scheduler、服务等)。如果你直接调用依赖于 Flutter 引擎的 API,而 Binding 还没初始化,就会报错。
ensureInitialized() 的作用
- 如果
WidgetsFlutterBinding已经初始化,就直接返回实例; - 如果还没初始化,就会创建一个新的
WidgetsFlutterBinding实例。
等价于:
if (WidgetsBinding.instance == null) {
WidgetsFlutterBinding();
}
常见使用场景
一般写在 main() 方法开头,尤其是当你在 runApp() 前需要执行一些依赖 Flutter 引擎的操作时:
void main() async {
// 确保 Flutter 引擎和框架初始化
WidgetsFlutterBinding.ensureInitialized();
// 比如使用插件:SharedPreferences、PathProvider、Firebase.initializeApp()
prefs = await SharedPreferences.getInstance();
runApp(MyApp());
}
什么时候必须要用
需要在 runApp() 之前调用 异步插件(这些插件底层需要引擎支持)。例如:
- 读取本地存储路径 (
path_provider) - 初始化 Firebase (
firebase_core) - 使用
SharedPreferences - 操作数据库 (如
sqflite)
如果不调用,可能会报类似:
ServicesBinding.defaultBinaryMessenger was accessed before the binding was initialized.
代码执行顺序
void main() async {
// 确保 Flutter 引擎和框架初始化
WidgetsFlutterBinding.ensureInitialized();
// 比如使用插件:SharedPreferences、PathProvider、Firebase.initializeApp()
prefs = await SharedPreferences.getInstance();
runApp(MyApp());
}
Flutter 引擎启动(C++ 层)
- 初始化 Dart 运行时
- 加载 Dart VM
- 加载你的
main.dart
Dart 层开始执行
- 进入你的
main()方法 - 此时Dart 层还没有任何 Binding 实例
- Flutter 框架(WidgetsBinding/RenderBinding 等)不会自动执行任何方法,因为这些都是通过 Dart 类实例化才会创建的
调用 WidgetsFlutterBinding.ensureInitialized()
- 检查
WidgetsBinding.instance - 如果 null → 创建一个
WidgetsFlutterBinding实例 - 如果已存在 → 直接返回实例
后续插件初始化和 runApp() 执行
从 Dart 层
main()开始到ensureInitialized()执行之前,不会有 Flutter 框架自动创建 Binding。所以,你这段时间里WidgetsBinding.instance一定是 null。也就是说,ensureInitialized()第一次被调用时,一定是主动创建 Binding。
gantt
title Flutter 程序启动流程时间线
dateFormat HH:mm:ss
axisFormat %H:%M:%S
section Flutter 引擎
启动引擎、初始化 Dart VM :a1, 00:00:00, 1s
section Dart 层
执行 main() :a2, after a1, 1s
手动调用 WidgetsFlutterBinding.ensureInitialized() :a3, after a2, 1s
─> 如果调用,Binding 立即创建 :a4, after a3, 0.5s
插件初始化(如 SharedPreferences):a5, after a4, 1s
runApp(MyApp()) :a6, after a5, 1s
─> 如果没有手动调用 ensureInitialized :a7, after a6, 0.5s Binding 在 runApp 内被创建
Binding 是什么时候创建的?
runApp() 内部会调用 WidgetsFlutterBinding.ensureInitialized()
在 runApp() 源码里:
WidgetsFlutterBinding.ensureInitialized();
所以如果你没有手动调用 ensureInitialized(),Binding 会在 runApp() 内部被创建。
注意:这就意味着任何在 runApp() 之前调用依赖 Binding 的操作(比如插件初始化、平台通道调用)都会失败。
| 情况 | Binding 创建时机 | 安全调用插件 |
|---|---|---|
手动调用 WidgetsFlutterBinding.ensureInitialized() |
main() 里调用时,立即创建 |
runApp() 前就可以安全调用 |
| 不手动调用 | runApp() 内部才创建 |
runApp() 前的插件调用可能报错情况 |