示例工程移动开发【免费下载链接】Flutter-NotebookFlutterDemo合集今天你fu了吗项目地址https://gitcode.com/gh_mirrors/fl/Flutter-Notebook点击查看免费下载本文以 Flutter-Notebook 仓库中的 event_bus_demo 为范例系统讲解如何使用 Dart 的event_bus包构建全局事件总线并通过rxdart的BehaviorSubject扩展其能力实现两个独立页面之间计数器状态的实时同步。读完本文你将掌握事件定义、Bus 单例创建、fire发送事件、onT()监听事件以及用StreamBuilder将事件流与 UI 绑定的完整实战链路并理解普通EventBus与自定义 Controller 的差异及适用场景。一、为什么需要 EventBusFlutter 页面间通信的痛点在 Flutter 应用中页面Route之间往往需要共享状态。官方推荐的方式是通过构造参数逐层向下传递、使用InheritedWidget、Provider或Bloc等方案。但当页面层级较深、页面数量较多时一层层传参会让代码耦合严重而当一个状态需要在多个互不相干的页面中被同时更新和展示时例如购物车数量、登录状态、消息未读数传统的回调与参数传递方式会变得难以维护。EventBus事件总线正是为了解决这类一对多的解耦通信而设计的事件的发送方与接收方完全解耦。发送方只需fire一个事件对象任何订阅了该事件类型的接收方都会收到通知双方互不依赖。本仓库的 event_bus_demo 就演示了这一场景FirstScreen与SecondScreen两个页面之间没有直接引用关系却通过同一个事件流共享并同步一个计数器。二、添加依赖在 pubspec.yaml 中引入 event_bus 与 rxdartevent_bus_demo 的依赖声明位于其 pubspec.yamldependencies: flutter: sdk: flutter cupertino_icons: ^0.1.2 event_bus: ^1.1.0 rxdart: ^0.21.0event_bus官方事件总线库提供EventBus类与fire/on两个核心 API。rxdartReactive Extensions for Dart这里用于为 Bus 注入BehaviorSubject让新订阅者能够立即收到最近一次事件详见下文自定义 Controller一节。添加后执行flutter pub get即可完成安装。需要说明的是仓库 README 提到作者曾向dart-event-bus提交过一个 PRissue #21并已被合并本 demo 正是该扩展能力的落地实践该 PR 的核心就是支持传入自定义 StreamController使 Bus 能对接 rxdart 等响应式流。三、定义事件类型让每个事件成为一等公民与基于字符串命名的事件总线不同event_bus采用强类型事件设计事件就是一个普通的 Dart 类。demo 中定义的事件位于 events/count_events.dartclass CountEvent { final int count; CountEvent(this.count); }CountEvent携带一个int count字段代表当前计数。在 event_bus 中事件的类型Type天然就是订阅的频道标识发送方fire(CountEvent(...))接收方onCountEvent()只接收该类型的事件其他类型的事件互不干扰。相比字符串 key 的广播机制强类型方案拥有更好的编译期检查和可读性。四、创建 Bus 单例默认控制器与自定义 Controller 对比4.1 最简写法默认 EventBusevent_bus包最基础的用法是直接实例化一个全局单例import package:event_bus/event_bus.dart; EventBus eventBus EventBus();默认构造器内部使用StreamController.broadcast()其特点是只广播订阅之后发生的事件——如果事件在订阅之前就已经fire后来订阅的监听者将永远收不到它。4.2 demo 的增强写法注入 BehaviorSubjectevent_bus_demo 在 tools/bus.dart 中使用了rxdart的自定义控制器import package:event_bus/event_bus.dart; import package:rxdart/rxdart.dart; EventBus behaviorBus EventBus.customController(BehaviorSubject());这里通过EventBus.customController(...)传入一个BehaviorSubject获得了两个关键增强缓存最近一次事件BehaviorSubject会记住最近发出的事件新订阅者一旦订阅会立刻收到该历史最新值而不是等待下一次fire。与响应式流生态打通Bus 的事件流可以直接使用 rxdart 的各类操作符如map、where、debounce等进行加工。这一改动正是 README 中所说的使用 rxdart 扩展了 bus 的功能的直接体现。它的实际价值在于页面 A 在页面 B 触发事件之前就已经完成初始化当用户从 B 返回 A 时A 的StreamBuilder重新订阅即可立即拿到当前最新计数而不会显示空白等待状态。五、发送与监听fire 与 on 的核心用法event_bus的 API 极其精简只有两个核心方法发送事件eventBus.fire(event)把事件对象广播给所有订阅者监听事件eventBus.onT()返回一个StreamT配合listen或StreamBuilder消费。在 demo 的 second_screen.dart 中点击右下角加号按钮会发送一个计数 1 的新事件floatingActionButton: FloatingActionButton( onPressed: () { if (snapshot.hasData) behaviorBus.fire(CountEvent(snapshot.data.count 1)); }, child: Icon(Icons.add), ),而在 first_screen.dart 中则是用StreamBuilder订阅事件流body: Center( child: StreamBuilderCountEvent( stream: behaviorBus.onCountEvent(), builder: (context, snapshot) { return snapshot.hasData ? Text(you pushed the button ${snapshot.data.count} times) : Text(waiting for data); }, ), ),注意snapshot.hasData分支若尚未收到任何事件界面显示waiting for data收到事件后则展示当前计数。StreamBuilder会在事件流每次产生新值时自动重建 UI这正是事件驱动 UI 刷新的关键。六、主入口初始化runApp 之后广播初始状态event_bus_demo 的 main.dart 有一个值得注意的设计在runApp之后立即fire一个初始事件void main(){ runApp(App()); behaviorBus.fire(CountEvent(0)); }class App extends StatelessWidget { override Widget build(BuildContext context) { return MaterialApp( title: Flutter Demo, theme: ThemeData.dark(), home: FirstScreen(), ); } }由于 Bus 使用的是BehaviorSubject这次CountEvent(0)会被缓存下来后续FirstScreen与SecondScreen中的StreamBuilder在挂载/重新订阅时都会立即收到count 0的初始值从而避免waiting for data长时间滞留。这一行代码体现了用 BehaviorSubject 做状态缓存的典型手法事件流不止是通知机制还充当了全局状态的持有者。七、完整链路两个页面如何做到状态实时同步把上面的代码串起来整个跨页面同步的调用链如下main()启动应用behaviorBus.fire(CountEvent(0))把初始计数 0 写入事件总线App以FirstScreen为首页其StreamBuilder订阅behaviorBus.onCountEvent()立即渲染出you pushed the button 0 times点击FirstScreen的导航按钮Navigator.push进入SecondScreen后者同样通过StreamBuilder订阅同一事件流因此也显示计数 0——两个页面展示的是同一份状态在SecondScreen点击加号behaviorBus.fire(CountEvent(count 1))发出新事件FirstScreen若仍在栈中与SecondScreen的StreamBuilder同时收到新值并刷新计数同步递增。整个过程没有任何页面间的直接传参或回调引用FirstScreen与SecondScreen的唯一交集就是全局的behaviorBus单例这正是事件总线解耦价值的直观体现。工程上事件定义统一放在 events/ 目录、Bus 单例独立放在 tools/bus.dart这种按职责分目录的组织方式也值得在真实项目中借鉴。八、验证与测试仓库自带的冒烟测试demo 目录下还带有一个 Flutter 冒烟测试 test/widget_test.darttestWidgets(Counter increments smoke test, (WidgetTester tester) async { await tester.pumpWidget(App()); expect(find.text(0), findsOneWidget); expect(find.text(1), findsNothing); await tester.tap(find.byIcon(Icons.add)); await tester.pump(); expect(find.text(0), findsNothing); expect(find.text(1), findsOneWidget); });测试逻辑与 demo 的交互路径一致先验证初始计数为 0再模拟点击加号按钮后计数变为 1。运行flutter test即可执行。需要留意的是该测试断言依赖App启动后behaviorBus.fire(CountEvent(0))写入的初始值——这也印证了BehaviorSubject 缓存最近事件、订阅者立即收到的行为对整个应用包括测试环境的一致性至关重要。九、实践要点与注意事项基于本 demo 的完整实现可以提炼出几条可直接复用的工程经验全局单例 独立文件把 Bus 实例放在独立工具文件中如tools/bus.dart导出避免在多个页面重复创建实例导致事件发不出去。强类型事件优于字符串事件event_bus按Type路由事件事件类建议做成不可变final字段保证数据一致性。订阅时机与生命周期StreamBuilder会在组件重建时自动管理订阅但若使用listen手动订阅务必在dispose中取消订阅subscription.cancel()避免内存泄漏。BehaviorSubject 的双刃剑它能缓存最近事件、避免订阅者错过更新但也会让陈旧值在新订阅者首次接入时立即触发一次回调若某些页面不希望在订阅时立即收到旧值应改用默认EventBus()或注入普通广播流。版本兼容性demo 使用event_bus ^1.1.0与rxdart ^0.21.0且工程声明sdk: 2.1.0 3.0.0在较新的 Flutter/Dart 环境中复刻时应根据当前 SDK 调整依赖版本。十、总结event_bus_demo 用不到 60 行业务代码完整呈现了事件总线驱动跨页面状态同步这一经典模式以event_bus的fire/onT为基础通信原语以 rxdart 的BehaviorSubject注入最近事件缓存能力再以StreamBuilder将事件流无缝接入 Flutter 声明式 UI。对于需要在多个页面间共享可变状态、又不希望引入重型状态管理框架的场景这是一个轻量、可靠、易于理解的替代方案其完整的可运行工程位于 mecury_project/example/event_bus_demo可直接作为新项目的起点模板。赞分享示例工程移动开发【免费下载链接】Flutter-NotebookFlutterDemo合集今天你fu了吗项目地址https://gitcode.com/gh_mirrors/fl/Flutter-Notebook点击查看免费下载相关推荐Flutter-Notebook页面状态KeepAlive实现多页面状态保持Flutter Notebook页面状态KeepAlive实现多页面状态保持 在Flutter应用开发中页面切换时状态丢失是常见问题。用户在Tab页间切换时示例工程移动开发Flutter-Notebook状态管理BLoC事件与状态设计Flutter Notebook状态管理BLoC事件与状态设计 BLoCBusiness Logic Component业务逻辑组件是Flutter中主示例工程移动开发Egg 事件总线 EventBus 实战指南基于类型安全的模块解耦与异步事件机制Egg 事件总线 EventBus 实战指南基于类型安全的模块解耦与异步事件机制 在 Egg 框架与 tegg 模块化体系中EventBus 消息中枢提供了后端Web框架创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?