Flutter 3.7 船新功能之后台隔离通道(终于等到你!)
介绍
从任何隔离使用插件和平台通道的需求自 2018 年以来一直存在。但是之前它被取消了优先级,因为其实现并不简单,虽然有一个解决方法,但是很麻烦:始终使用根隔离(Flutter 提供的 isolate)中的插件。然而,随着 Flutter 的成熟,它越来越关注性能,遵循古老的软件格言 让它工作,让它正确,让它快速
。选择现在选择实现此功能是提高性能和使 Flutter 更易于使用的一个愉快的交汇点。。
从 Flutter 3.7 开始,开发人员可以从任何隔离使用插件和平台通道。
用例
想象一个使用 AI 从文本提示生成高分辨率图像的应用程序。用户之前的创作存储在 Firebase 云存储中,并且具有从用户手机导出和共享创作的功能。Flutter 应用启动一个背景隔离,从 Firebase Cloud Store 下载 8k 版本的图像,将图像缩小采样到所需的导出大小,将图像保存到相机胶卷,最后在导出完成时发布本地通知。
在此示例中,至少使用了 3 个来自后台隔离的插件,一个用于从 Firebase Cloud Store 读取,一个用于保存到手机的相机胶卷,另一个用于发布本地通知。如果没有背景隔离通道,应用程序必须将 8k 图像从根隔离复制到背景隔离,以便对其进行下采样。目前(2023-02-04)的 Dart 没有办法让它成为一个恒定的时间操作。
示例
下面一个使用新 API 从后台隔离调用 shared_preferences 插件的示例:
1import "package:flutter/services.dart";
2import "package:shared_preferences/shared_preferences.dart";
3
4void main() {
5 // 确定要传递给后台隔离的根隔离。
6 // (Flutter 3.7 中引入的 API)
7 RootIsolateToken rootIsolateToken = RootIsolateToken.instance!;
8 Isolate.spawn(_isolateMain, rootIsolateToken);
9}
10
11void _isolateMain(RootIsolateToken rootIsolateToken) async {
12 // 将背景隔离注册到根隔离。
13 BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);
14 // 现在可以使用 shared_preferences 插件了。
15 SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
16 print(sharedPreferences.getBool("isDebug"));
17}
技术细节
平台通道工作原理的高级概述
调用 平台通道(platform channel)
的结果时,会有一个到 平台线程(platform thread)
的硬编码跳转。为了使后台隔离通道工作,必须存储发送消息的隔离,以便引擎可以在该隔离的事件循环上安排结果。这是通过使用 Dart 端口 实现的。Dart 端口会存储拥有它的隔离,那是从 C API 调度这些隔离的唯一方法。
另一件事是将 后台隔离(background isolate)
与其 根隔离(root isolate)
相关联的方式。为了在 Flutter 引擎被破坏时关闭平台通道,必须知道哪些背景隔离与该引擎相关联。否则,后台隔离可能会尝试与正在被销毁的 Flutter 引擎通信。这方面的影响可以在最终的 API 中看到,其要求必须使用一个 RootIsolateToken
来初始化 BackgroundIsolateBinaryMessenger
。
番外
有关实现的更多信息,可以查看 隔离平台通道 设计文档。该文档还包含在相反方向进行通信的建议(但尚未实施或接受)。