一、EventBus 事件总线
在App中,我们经常会需要广播机制,用以跨页面事件通知,比如一个需要登录的App中,页面会关注用户登录或者注销事件,来进行一些状态更新。这时候,一个事件总线便会非常有用,事件总线通常实现了订阅模式,订阅者模式包含了发布者和订阅者两种角色,可以通过事件总线来触发事件和监听事件, 下面我们实现一个简单的全局事件总线,使用单例模式。
二、代码实现
//event_bus.dart
//订阅者回调签名
typedef void EventCallback(arg);
class EventBus {
//私有构造函数
EventBus._internal();
//保持单例
static EventBus _singleton = EventBus._internal();
//工厂构造函数
factory EventBus() => _singleton;
//保存事件订阅者队列,key: 事件名成 value:对应的事件订阅者队列
final _emap = Map<Object, List<EventCallback>>();
//添加订阅者
void on(eventName, EventCallback f) {
_emap[eventName] ??= <EventCallback>[];
_emap[eventName].add(f);
}
//移除订阅者
void off(eventName, [EventCallback f]) {
var list = _emap[eventName];
if (eventName == null || list == null) {
return;
}
if (f == null){
_emap[eventName] = null;
} else {
list.remove(f);
}
}
//触发事件,事件触发后该事件所有订阅者会被调用
void emit(eventName, [arg]) {
var list = _emap[eventName];
if (list ==null) return;
int len = list.length-1;
//反向遍历,防止订阅者在回调中移除自身带来的下标错位
for (var i=len; i>-1; --i){
list[i](arg);
}
}
}
//定义一个top-level(全局)变量,页面A中订阅者会被调用
var bus = EventBus();
import 'package:flutter/material.dart';
import 'event_bus.dart';
class EventBusAPage extends StatefulWidget {
const EventBusAPage({Key key}) : super(key: key);
@override
_EventBusAPageState createState() => _EventBusAPageState();
}
class _EventBusAPageState extends State<EventBusAPage> {
var data ='';
@override
void initState() {
super.initState();
bus.on("doAction", (arg){
print('doAction $arg');
data = arg;
setState(() {
});
});
}
@override
void dispose() {
super.dispose();
bus.off('doAction');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('EventBusPageA'),
),
body: Container(
child: Column(
children: [
MaterialButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context){
return EventBusBPage();
}));
},
child: Text('跳转到PageB'),
),
Text(data, style: TextStyle(color: Colors.black, fontSize: 16),
)
],
),
),
);
}
}
class EventBusBPage extends StatefulWidget {
const EventBusBPage({Key key}) : super(key: key);
@override
_EventBusBPageState createState() => _EventBusBPageState();
}
class _EventBusBPageState extends State<EventBusBPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('EventBusPageB'),
),
body: Container(
child: Column(
children: [
MaterialButton(
onPressed:()=> bus.emit('doAction', "hello PageA from PageB"),
child: Text('更新页面A的数据'),
),
],
),
),
);
}
}
效果如下: