Isolates 在 Flutter 3.7 & Dart 2.19 的升級,你該知道一下!
Isolate is a good friend
隔離在 Flutter 是個很重要的角色,讓我們可以藉由它處理一些繁重的任務,例如:文字解析、圖像處理或是大量的資料存取,適當的使用可以避免 Main isolate 的阻塞,讓 APP 在運行時更為順暢。
本篇告訴你在近期的 Flutter 與 Dart 改版後,Isolate成長了多少, 有哪些新 API 和功能,快速了解一下吧。
1. RootIsolateToken
從 Flutter 3.7 開始,可以在其他 background isolates 使用任何套件(ex: SharedPreferences
)以及 Platform Channel。
情境:A 啟動一個 background isolate,從 Firebase Cloud Store 下載 8k 圖像,將它壓縮到所需的導出大小,接著將圖像保存到手機相簿,最後在完成時發布本地通知
下載、壓縮圖像、發送通知都使用 isolate 在背景處理,可以確保不影響 main isolate,但同時又能透過套件執行一些任務
實作範例
首先將 Root isolate 傳遞給 other isolates,讓 isolates 可以透過 Root isolate 進行初始化,代表兩者產生關聯,接著就可以存取套件了,例如:取得 flutter_secure_storage
資料、發送 flutter_local_notifications
本地通知
一開始我們創建 RootIsolateToken 以及 ReceivePort 實體,RootIsolateToken 要給 isolates 進行通訊的初始化,而 ReceivePort 為了接收 isolates 返回的結果。使用 Isolate.spawn
創建 isolate,給予執行函式和關鍵參數
void main() {
// 將 RootIsolateToken 傳遞給 background isolate 使用
RootIsolateToken rootIsolateToken = RootIsolateToken.instance!;
ReceivePort receivePort = ReceivePort();
Isolate.spawn(_isolateGetData, [rootIsolateToken, receivePort.sendPort]);
}
在 isolate 接收兩個參數,並執行 ensureInitialized()
初始化RootIsolateToken,接著就能使用套件做一些處理,例如要從 FirebaseFirestore 取資料也行。最終再將訊息、數據經由 SendPort 回傳給 main isolate 使用,完成隔離的背景操作
void _isolateGetData(List<Object> args) async {
final rootIsolateToken = args[0] as RootIsolateToken;
final sendPort = args[1] as SendPort;
// 使用 RootIsolateToken 註冊 background isolate
BackgroundIsolateBinaryMessenger
.ensureInitialized(rootIsolateToken);
// 接下來就可以存取套件了
SharedPreferences sharedPreferences =
await SharedPreferences.getInstance();
...
// 取得結果後再透過 SendPort 返回 Main isolate
// sendPort.send(result);
}
BackgroundIsolateBinaryMessenger.ensureInitialized()
是最重要的環節,讓 isolate 可以跟 Root isolate 產生連結,綁定生命週期,在 APP 和 Flutter Engine 銷毀時可以關閉 Platform Channel,避免其他 isolates 嘗試跟 Flutter engine 溝通,造成不必要的消耗
2. Isolate.run()
run()
為一個更簡單且強大的 Api,省略原本使用 isolate 的複雜代碼,可替代原有的compute()
操作- 不需要 SendPort、ReceivePort,也不用維護 isolate 的創建、銷毀,甚至錯誤捕捉都已經處理好了,只需要一般情境的 try catch 即可
- 除了可以處理非同步的函式外,也支援同步處理,回傳值一律都為 Future
- 函式參數可以使用匿名函式,不需要特別使用全域和靜態
- 最後使用
exit()
將在 background isolate 中處理的結果內存回傳給 main isolate (不需要因為複製而導致佔用記憶體),然後安全地銷毀 isolate - 適合情境:一次性的任務處理
void main() async {
try {
final jsonData = await Isolate.run(_readAndParseJson);
} catch (error, stackTrace) {
debugPrint("$error , $stackTrace");
}
}
注意:如果應用是有支援 Native 平台跟 Web,會建議使用
compute()
,在所有環境才能正常運作。如果確定只支援 Native 平台,就可使用run()
高級 API
Conclusion
現在有了 Flutter 3.7 和 Dart 2.19,我們可以在提升 App 性能表現之外更精準的使用套件、存取原生平台的功能,趕快在專案上適當地使用它們吧!
Reference
- 學會運用 Flutter Widgetbook,該管好自己和公司的元件庫了!
- 剛進入 Flutter 嗎?適合初學者食用,GetX 是否適合你呢!
- 教你為 Riverpod 2.0 撰寫 Flutter 測試 part.1
- 教你為 Riverpod 2.0 撰寫 Flutter 測試 part.2
- 輕鬆了解 Isar NoSQL DB,用它來實作 Flutter 資料庫吧!
- Flutter 輕鬆實作 i18n,使用 easy_localization_generator 就對了
- Flutter CICD 使用 Gitlab Runner 和 App Center 實作 part.1
- Flutter CICD 使用 Gitlab Runner 和 App Center 實作 part.2
- 使用 CodeMagic 和 Firebase 實現 Flutter CICD
- 輕鬆完成Flutter開發環境,最新版!
- 實作Flutter多變有趣的滾動效果CustomScrollView!
- 如何在Flutter使用 Makefile 節省你的時間?
- Easily understand StatefulWidget LifeCycle of Flutter
- “freezed” makes model class strong and easily
- 提高Flutter性能的小技巧!(一)
- 提高Flutter性能的小技巧!(二)
- 提高Flutter性能的小技巧!(三)
- What are Async and Isolates in Flutter?
- LoadBalancer is optimization for Isolates in Flutter
- Riverpod 輕鬆學,原來這麼好用!
- Riverpod 輕鬆學(二),一些進階用法!
About
- GitHub: chyiiiiiiiiiiii
- Instagram: flutterluvr.yii
- Linkedin: yiichenhi
- Youtube: Yii
- Youtube: 一起饅頭(美食頻道)
- Email: ab20803@gmail.com
Contribution
如果覺得文章不錯的話可以贊助,讓我有更多動力和熱情分享學習紀錄和生活!請我喝一杯咖啡吧~
希望有幫助到你/妳,歡迎追蹤我,方便瀏覽最新的文章~