在APP中,我们经常会需要一个广播机制,用以跨页面事件通知,比如一个需要登录的APP中,页面会关注用户登录或注销事件,来进行一些状态更新。这时候,一个事件总线便会非常有用,事件总线通常实现了订阅者模式,订阅者模式包含发布者和订阅者两种角色,可以通过事件总线来触发事件和监听事件,我们实现一个简单的全局事件总线,我们使用单例模式。
广播工具类,代码如下:
//订阅者回调签名
typedef void EventCallback(arg);
class EventBus {
//私有构造函数
EventBus._internal();
//保存单例
static EventBus _singleton = new EventBus._internal();
//工厂构造函数
factory EventBus()=> _singleton;
//保存事件订阅者队列,key:事件名(id),value: 对应事件的订阅者队列
var _emap = new Map<Object, List<EventCallback>>();
//添加订阅者
void addListener(eventName, EventCallback f) {
if (eventName == null || f == null) return;
_emap[eventName] ??= new List<EventCallback>();
_emap[eventName].add(f);
}
//移除订阅者
void removeListener(eventName, [EventCallback f]) {
var list = _emap[eventName];
if (eventName == null || list == null) return;
if (f == null) {
_emap[eventName] = null;
} else {
list.remove(f);
}
}
//触发事件,事件触发后该事件所有订阅者会被调用
void sendBroadcast(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变量,页面引入该文件后可以直接使用bus
var bus = new EventBus();
使用
B页面发送广播:
bus.sendBroadcast("login", '登录');
A页面:
添加监听
@override
void initState() {
super.initState();
//监听登录事件
bus.addListener("login", (arg) {
setState(() {
_lodinState = '通知我登录成功了';
});
});
bus.addListener("logout", (arg) {
setState(() {
_logoutState = '通知我退出登录成功了';
});
});
}
移除广播机制
@override
void dispose() {
super.dispose();
bus.removeListener("login");//移除广播机制
bus.removeListener("logout");//移除广播机制
}
A页面全部代码
import 'package:flutter/material.dart';
import 'package:flutter_broadcast/broadcast_utils.dart';
import 'package:flutter_broadcast/login_logout.dart';
import 'package:flutter_broadcast/utils.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '广播demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _lodinState;
String _logoutState;
@override
void initState() {
super.initState();
//监听登录事件
bus.addListener("login", (arg) {
setState(() {
_lodinState = '通知我登录成功了';
});
});
bus.addListener("logout", (arg) {
setState(() {
_logoutState = '通知我退出登录成功了';
});
});
}
@override
void dispose() {
super.dispose();
bus.removeListener("login");//移除广播机制
bus.removeListener("logout");//移除广播机制
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('广播demo'),
),
body: Container(
child: ListView(
children: <Widget>[
Container(
alignment: Alignment.topCenter,
child: FlatButton(
onPressed: () {
Utils.turn(context, BroadcastPage());
},
child: Text('跳转'))
),
Container(
margin: EdgeInsets.only(top: 20),
alignment: Alignment.topCenter,
child: Text(
_lodinState != null ? _lodinState : '',
),
),
Container(
margin: EdgeInsets.only(top: 20),
alignment: Alignment.topCenter,
child: Text(
_logoutState != null ? _logoutState : '',
),
),
],
),
)
);
}
}
B页面全部代码
import 'package:flutter/material.dart';
import 'package:flutter_broadcast/utils.dart';
import 'broadcast_utils.dart';
class BroadcastPage extends StatefulWidget {
@override
BroadcastPageState createState() => new BroadcastPageState();
}
class BroadcastPageState extends State<BroadcastPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('登录 注销'),
),
body: Container(
child: ListView(
children: <Widget>[
Container(
alignment: Alignment.topCenter,
child: FlatButton(
onPressed: () {
//登录成功后触发登录事件,页面A中订阅者会被调用
bus.sendBroadcast("login", '登录');
Utils.pop(context);
},
child: Text('登录'))
),
Container(
alignment: Alignment.topCenter,
child: FlatButton(
onPressed: () {
bus.sendBroadcast("logout",'退出登录');
Utils.pop(context);
},
child: Text('退出登录'))
),
],
),
),
);
}
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
@override
void didUpdateWidget(BroadcastPage oldWidget) {
// TODO: implement didUpdateWidget
super.didUpdateWidget(oldWidget);
}
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
}
}
网友评论