如何用FRB(flutter_rust_bridge)快速搭建Flutter+Rust混编项目
关注专栏,一起学习。
在开发高性能、实时交互应用时,数据的高效传输与处理至关重要。 今天就来聊聊,如何让 Flutter 从 Rust 中丝滑接收 Stream 数据流,彻底告别阻塞烦恼!
01. 为什么需要 Flutter 从 Rust 接收 Stream 数据流?
在很多场景下,我们需要持续获取数据更新,比如实时聊天消息、股票价格变动、传感器数据采集等。 如果使用传统的单次数据传输方式,不仅效率低下,还可能导致数据丢失或延迟。 而 Stream 数据流就像一条源源不断的河流,能够持续、有序地将数据推送给接收方。
Rust 以其出色的性能和内存安全性,非常适合处理底层数据采集和复杂计算任务。 Flutter 则擅长构建精美、流畅的用户界面。 将两者结合,让 Rust 负责生产数据流,Flutter 负责展示数据,能充分发挥各自优势,打造出体验极佳的应用。
02. 案例说明
Rust 端:用文件系统API获取目录内容列表 Flutter 端:调用 Rust 函数并显示目录列表
在这个场景下,不同目录下的内容列表数量有非常大的差异,内容最少的是空目录,而多的可能高达上千甚至上万个项目。 这个区别导致调用同一个函数时,返回最终数据所需时间会随着目录内容项多少而产生很大浮动。 调用方如果每次调用都等待全部数据返回是不现实的,反映到界面上就是肉眼可见的卡顿或等待加载时间条。
Stream的机制可以完美解决这个问题,通过将数据流式传输,我们可以逐步接收目录内容,而不是等待所有数据一次性返回。 这样可以显著减少等待时间,提升用户体验。
03. 代码实践
本文依然基于Flutter Rust Bridge(FRB)这个库来实现 Flutter 与 Rust 的高效通信。 FRB 提供了一种简洁且高效的方式来桥接 Flutter 和 Rust,使得我们可以充分利用 Rust 的高性能和内存安全特性,同时结合 Flutter 强大的 UI 开发能力。
a. Rust端实现
Rust端我们采用文件系统模块std::fs的相关API来实现,通过参考FRB文档Stream数据处理章节,以下代码可以实现以Stream的形式读取并发送目录内容项:
首先定义一个目录内容项
Struct,最终会转译成Dart的Class。
然后实现读取目录内容列表的函数
第一个参数传入泛型参数为上边
FsEntity结构的StreamSink对象,StreamSink是FRB生成的胶水结构第二个参数为
Flutter端调用时需要传入的实际参数指定目录路径字符串如函数无需关心返回值,设置为
Result<()>,最后返回Ok(())即可
b. 执行FRB代码生成命令
在FRB生成的项目结构根目录下,执行
flutter_rust_bridge_codegen generate --watch
即可把上边的Rust代码Struct和函数转译出Flutter可以直接调用的API文件和代码。
可以看到,生成的代码中:
Struct对应Class,
生成的Dart函数稍微有点儿不同,Rust端函数里第一个参数StreamSink变成了Dart里的Stream成了返回值,其他参数没有变化成了Dart函数的关键字参数。
c. Flutter端代码
首先在组件类声明一个
Stream流数据对象
late Stream<FsEntity> _fsEntitiesStream;
再调用Rust端转译的函数
getFsEntities,更新State后,开启Stream订阅
var fsEntitiesStream = getFsEntities(rootPath: "D:\\somedir\\");
setState(() {
_fsEntitiesStream = fsEntitiesStream;
});
_fsEntitiesStream.listen((evt) {
// 这里接收的evt即为Rust端代码以Stream流形式发送的FsEntity对象
setState(() {
// 此处可以处理更新Widget数据State的值,通知对应界面元素更新显示。
// ...
});
});
04. 总结
从案例实践可以看出,FRB作为Flutter和Rust的中间绑定层,对于业务层实现来说,提供了极大的便利和灵活性。 它不仅简化了跨语言通信的复杂性,还通过高效的数据传输机制,使得 Flutter 和 Rust 可以无缝协作。 这种协作方式在处理大量数据和高性能需求时,表现尤为突出。
本专栏专注Rust和Flutter深度协作实践,欢迎关注和交流。