一、前言
EventBus
是全局事件总线,底层通过Stream
来实现;它可以实现不同页面的跨层访问,通过Stream
的机制来实现不同widget
之间的状态共享.
二、作用
- 举个例子:
你有一个主界面,里面有一些信息可能会修改,但触发源不在该界面,是在其他的界面触发了一些事件后,首页的内容需要做修改。如果没有
EventBus
,也有很多的方式可以实现,譬如定义全局静态变量、或者定义个CallBack
接口传出去等等。不管怎样,总是要把主页和触发源关联起来,这是相当难受的,这不但会导致代码量暴涨,同时还会导致耦合度极高,不得不写的这个引用让人如鲠在喉。
三、使用
在
flutter
中使用eventbus
主要可以归纳为如下步骤:
- 实例化
eventbus
- 定义消息
event
对象 - 创建监听器
- 发送消息
- 接收消息
- 下文我将以网络请求为例进行解析
3.1 实例化 eventbus
- 由于
eventbus
是可能在不同类里调用的 - 就比如说本文的网络请求使用
eventbus
,那么网络请求可能发生在很多歌类的代码里 - 所以不能将其单独在某个特定页面的类里创建,而需要让其变成全局的变量
- 这里我们新建一个文件:
event_bus.dart
用它来专门存储event_bus
对象
import 'package:event_bus/event_bus.dart';
EventBus eventBus = new EventBus();
3.2 定义消息 event
对象
- 有学过
Android
、iOS
或者其他任意技术的同学都知道 - 在全局发送一个消息是需要携带一个对象,来存储消息的内容
- 其实
flutter
的event_bus
也是如此 - 所以我们新建一个文件
http_event.dart
来存放这种需要传递的消息体 - 当然本文限于篇幅,就以网络请求错误/失败为例
class HttpErrorEvent {
final int code;
final String message;
HttpErrorEvent(this.code, this.message);
}
3.3 创建监听器
- 跟 3.2 类似,我们针对每种类型的事件(每个
eventbus
),需要建立一个监听 - 并把这个监听混入相应的页面(
widget
中)来达到监听效果 - 所以,我们首先新建一个文件
http_listener.dart
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'event_bus.dart';
import 'home_page.dart';
import 'http_event.dart';
mixin HttpErrorListener on State<MyHomePage> {
StreamSubscription stream;
BuildContext _context;
@override
void initState() {
super.initState();
///Stream演示event bus
stream = eventBus.on<HttpErrorEvent>().listen((event) {
errorHandleFunction(event.code, event.message);
});
}
@override
void dispose() {
super.dispose();
if (stream != null) {
stream.cancel();
stream = null;
}
}
///网络错误提醒
errorHandleFunction(int code, message) {
switch (code) {
case 404:
showToast("404: ${message}");
break;
default:
showToast("unknown: ${message}");
break;
}
}
showToast(String message) {
Fluttertoast.showToast(
msg: message,
gravity: ToastGravity.CENTER,
toastLength: Toast.LENGTH_LONG);
}
}
- 这里使用 私有的
_context
是因为此时State
的context
是FlutterReduxApp
而不是MaterialApp
- 所以如果直接用
context
是会获取不到MaterialApp
的Localizations
哦。
showToast
是一个三方的吐司库 可以再dependences
中添加fluttertoast: ^7.1.1
即可
3.4 发送消息
- 发送消息时只要调用
eventBus.fire(...)
即可 - 参数是需要传递的消息对象
- 比如本文的玩过请求失败就可以是
HttpErrorEvent(404, "找不到网页")
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
@override
void dispose() {
super.dispose();
}
void _incrementCounter() {
eventBus.fire(HttpErrorEvent(404, "找不到网页"));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Text(
'flutter event bus sample',
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
3.5 接收消息
- 接收消息其实就是把监听器混入的过程
- 混入对象可以是一个单例(比如收到消息后上传日志,或者后台做什么动作),也可以是一个页面(比如刷新下页面,或者本文网络请求的例子,请求失败需要弹出一个
Toast
),等等诸如此类 - 这里就按网络请求的例子,我们在
State
对象后混入:with HttpErrorListener
即可
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with HttpErrorListener {
// ...
}
- 这样一来,当 3. 4 中发送消息后,
_MyHomePageState
的监听就会收到消息对象 - 并调用
HttpErrorListener
中的errorHandleFunction
方法去触发其中的showToast(String message)
方法,从而在屏幕上弹出一个Toast
为了方便大家理解,对于
Dart
中混合mixin、on、with
语法陌生的同学可以看这篇文章 Flutter 知识梳理 (Dart) - implements, extends, mixin 的理解
四、总结
- 对于复杂的程序
event_bus
能有效的解耦,把本该有联系的需要传引用的给简化了,由它来分发事件了。这在某些时候和Android
里的broadcast
有点像,都是能通知很多个观察者,只不过更简便一点。 - 为了方便大家学习,我把代码上传到了
github
:bilibili-workspace/flutter_eventbus_sample - 如果还有疑问,或者有更好的方法,欢迎大家在评论区提出
- 感谢大家的三连或者关注支持,我们下期文章再见