Last Updated on 2021-10-13 by Clay
在使用 Flutter 開發 APP 時,若是碰到像是 firebase 或 sqflite 等套件需要初始化時,但偏偏它們又是非同步(asynchronously)操作時,往往會讓我們得到以下報錯訊息:
ServicesBinding.defaultBinaryMessenger was accessed before the binding was initialized.
我們可以看到以下這張 Flutter 的架構圖,其中分成 Framework、Engine、Embedder 等數個不同的區塊,每個區塊中又有各種模組與功能。
而像是 firebase 與 sqflite 等套件正是需要這些模組與功能來完成初始化。但正如上方所述,這些操作是非同步的。所以,我們必須確保,一個叫做 WidgetsBinding 的物件已經被初始化、建立起來。
這樣一來,這些非同步初始化的套件才能正常工作。
解決方法
說穿了,其實解決問題並不複雜。我們可以想像成以下簡化的流程:
- 我們有個 A 工具,需要 B 工具才能運作
- A 工具會比 B 工具更早載入 => 程式報錯!
- 我們先寫段程式確保 B 工具載入,再載入 A 工具 => 程式成功運行!
也就說,我們可以在以下的程式碼中,加入:
WidgetsFlutterBinding.ensureInitialized();
以此來確保 WidgetsBinding 已經初始化。
整體程式碼看起來會長得像以下這段程式碼:
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
void main() async {
// Avoid errors
WidgetsFlutterBinding.ensureInitialized();
// Open the database
final Future<Database> database = openDatabase(
// Ensure the path is correctly for any platform
join(await getDatabasesPath(), "Human_database.db"),
onCreate: (db, version) {
return db.execute(
"CREATE TABLE Human("
"id INTEGER PRIMARY KEY,"
"name TEXT,"
"age INTEGER,"
"FAT BOOLEAN)"
);
},
// Set the database version
version: 1,
);
print("OK!");
}
Output:
OK!
可以發現,拔掉以下這段程式碼
WidgetsFlutterBinding.ensureInitialized();
程式是會報錯的。
References
- https://stackoverflow.com/questions/63873338/what-does-widgetsflutterbinding-ensureinitialized-do
- https://api.flutter.dev/flutter/widgets/WidgetsFlutterBinding-class.html