EventBus介紹
在Android事件匯流排庫中,EventBus庫是最廣泛之一。 看看Android EventBus庫的說明 官網
- 釋出者/訂閱者模式
- 集中式通訊
- 低耦合,簡化元件通訊
自定義EventBus
我們要實現一個Flutter版的EventBus!功能如下:
- 註冊Subscriber到EventBus
- Publisher post Event,分發給Subscriber
- EventBus可以註冊多種型別的Event
Demo地址 入口 main_eventbus.dart
介面定義
//釋出者介面
abstract class IPublisher {
void post<T>(T event);
}
//訂閱者:函式物件
typedef ISubscriber<T> = void Function(T event);
//集中式通訊,
//1.IEventBus繼承IPublisher,分發資料
//2.IEventBus註冊和取消註冊ISubscriber
abstract class IEventBus extends IPublisher {
void register<T>(ISubscriber<T> subscriber);
void unregister<T>(ISubscriber<T> subscriber);
}
複製程式碼
介面實現1
Type typeOf<T>() => T;
class MyEventBus1 implements IEventBus {
//我們用map存放我們的訂閱者。不同訂閱者訂閱的Event型別可能是不同的
Map<Type, List<Function>> map = new Map();
@override
void register<T>(ISubscriber<T> subscriber) {
Type type = typeOf<T>();
if (!map.containsKey(type)) {
map[type] = new List();
}
map[type].add(subscriber);
}
@override
void unregister<T>(ISubscriber<T> subscriber) {
Type type = typeOf<T>();
if (map.containsKey(type)) {
map[type].remove(subscriber);
}
}
//釋出
@override
void post<T>(T event) {
Type type = typeOf<T>();
if (map.containsKey(type)) {
var subscribers = map[type];
subscribers?.forEach((subscriber) => subscriber?.call(event));
}
}
}
複製程式碼
介面實現2
class MyEventBus2 implements IEventBus {
List<Function> subscribers = new List();
@override
register<T>(ISubscriber<T> subscriber) {
if (!subscribers.contains(subscriber)) {
subscribers.add(subscriber);
}
}
@override
unregister<T>(ISubscriber<T> subscriber) {
if (subscribers.contains(subscriber)) {
subscribers.remove(subscriber);
}
}
@override
post<T>(T event) {
var ints = subscribers.whereType<ISubscriber<T>>();
ints?.forEach((subscriber) => subscriber?.call(event));
}
}
複製程式碼
功能測試
class EventX {}
class EventY {}
main() {
testEventBus(new MyEventBus1());
print("--------------------");
testEventBus(new MyEventBus2());
}
void testEventBus(IEventBus eventBus) {
ISubscriber<EventX> subscriber1 = (event) => print(event.toString());
ISubscriber<EventX> subscriber2 = (event) => print(event.toString());
eventBus.register(subscriber1);
eventBus.register(subscriber2);
eventBus.unregister(subscriber1);
ISubscriber<EventY> subscriber3 = (event) => print(event.toString());
ISubscriber<EventY> subscriber4 = (event) => print(event.toString());
eventBus.register(subscriber3);
eventBus.register(subscriber4);
eventBus.post(new EventX());
eventBus.post(new EventY());
}
複製程式碼
結果輸出為以下,測試通過
Instance of 'EventX'
Instance of 'EventY'
Instance of 'EventY'
--------------------
Instance of 'EventX'
Instance of 'EventY'
Instance of 'EventY'
複製程式碼
使用自定義EventBus
需求效果圖
點選每行的按鈕,每行上的兩個數字會增長1
程式碼實現
MyEventBus1 _eventBus = new MyEventBus1();
//首先我們定義event。第一排用EventA,第二排用EventB
class BaseEvent { int count = 0;}
class EventA extends BaseEvent {}
class EventB extends BaseEvent {}
//點選按鈕
class ButtonWidget<T extends BaseEvent> extends StatelessWidget {
final T event;
const ButtonWidget({Key key, this.event}) : super(key: key);
@override
Widget build(BuildContext context) {
return RaisedButton(
child: Text("increment"),
onPressed: _increment,
);
}
//點選處理
void _increment() {
if (event != null) {
event.count++;
_eventBus.post(event);
}
}
}
//顯示數字
class TextWidget<T> extends StatefulWidget {
@override
_TextWidgetState<T> createState() {
return _TextWidgetState<T>();
}
}
class _TextWidgetState<T> extends State<TextWidget<T>> {
int _count = 0;
ISubscriber<T> _subscriber;
@override
void initState() {
super.initState();
//通過setState 重新整理UI。
_subscriber =
(event) => setState(() => _count = (event as BaseEvent).count);
//註冊
_eventBus.register<T>(_subscriber);
}
@override
Widget build(BuildContext context) {
return Text(
" $_count ",
style: TextStyle(fontSize: 18),
);
}
@override
void dispose() {
super.dispose();
//取消註冊
_eventBus.unregister<T>(_subscriber);
}
}
//頁面主體
class EventBusDemoWidget1 extends StatefulWidget {
EventBusDemoWidget1({Key key}) : super(key: key);
@override
_EventBusDemoWidget1State createState() => _EventBusDemoWidget1State();
}
class _EventBusDemoWidget1State extends State<EventBusDemoWidget1> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(eventBusDemo1Title),
),
body: Container(
child: Column(
children: <Widget>[
Row(
children: <Widget>[
new ButtonWidget(event: new EventA()),
new TextWidget<EventA>(),
new TextWidget<EventA>()
],
),
Divider(
color: Colors.grey,
),
Row(
children: <Widget>[
new ButtonWidget(event: new EventB()),
new TextWidget<EventB>(),
new TextWidget<EventB>()
],
)
],
),
),
);
}
}
複製程式碼
自定義EventBus大功告成!再來看看別人家的EventBus。
pub上的EventBus
我們在pub.dev上找到了一個EventBus庫 ,github地址
An Event Bus using Dart Streams for decoupling applications
使用EventBus
實際相對於自定義的EventBus,不同點在ButtonWidget和TextWidget中。
class ButtonWidget<T extends BaseEvent> extends StatelessWidget {
final T event;
const ButtonWidget({Key key, this.event}) : super(key: key);
@override
Widget build(BuildContext context) {
return RaisedButton(
child: Text("increment"),
onPressed: _increment,
);
}
void _increment() {
if (event != null) {
event.count++;
print(event.count);
_eventBus.fire(event);
// _eventBus.post(event);
}
}
}
class TextWidget<T> extends StatefulWidget {
@override
_TextWidgetState<T> createState() {
return _TextWidgetState<T>();
}
}
class _TextWidgetState<T> extends State<TextWidget<T>> {
int _count = 0;
// ISubscriber<T> _subscriber;
StreamSubscription<T> _subscriber;
@override
void initState() {
super.initState();
// _subscriber =
// (event) => setState(() => _count = (event as BaseEvent).count);
// _eventBus.register<T>(_subscriber);
_subscriber = _eventBus
.on<T>()
.listen((event) => setState(() => _count = (event as BaseEvent).count));
}
@override
Widget build(BuildContext context) {
print(typeOf<T>());
return Text(
" $_count ",
style: TextStyle(fontSize: 18),
);
}
@override
void dispose() {
super.dispose();
// _eventBus.unregister<T>(_subscriber);
_subscriber.cancel();
}
}
複製程式碼
EventBus庫原始碼
class EventBus {
StreamController _streamController;
StreamController get streamController => _streamController;
EventBus({bool sync = false})
: _streamController = StreamController.broadcast(sync: sync);
EventBus.customController(StreamController controller)
: _streamController = controller;
Stream<T> on<T>() {
if (T == dynamic) {
return streamController.stream;
} else {
return streamController.stream.where((event) => event is T).cast<T>();
}
}
void fire(event) {
streamController.add(event);
}
void destroy() {
_streamController.close();
}
}
複製程式碼
EventBus庫之Stream
不禁感慨,Dart自帶Stream,處理非同步事件。Stream是Dart:async庫的核心API,對非同步提供了非常好的支援。 這裡簡單貼圖,體會下Stream。
值得注意的是這句話return streamController.stream.where((event) => event is T).cast<T>();
複製程式碼
返回的Stream包了兩層 CastStream(_WhereStream(_BroadcastStream),通過這樣的處理就可以監聽泛型事件了。
_WhereStream先處理
class _WhereStream<T> extends _ForwardingStream<T, T> {
final _Predicate<T> _test;
_WhereStream(Stream<T> source, bool test(T value))
: _test = test,
super(source);
//_test即為 (event) => event is T
void _handleData(T inputEvent, _EventSink<T> sink) {
bool satisfies = _test(inputEvent);
if (satisfies) {
sink._add(inputEvent);
}
}
}
複製程式碼
CastStreamSubscription實際做的型別轉換
class CastStreamSubscription<S, T> implements StreamSubscription<T> {
final StreamSubscription<S> _source;
/// User's data handler. May be null.
void Function(T) _handleData;
CastStreamSubscription(this._source) {
_source.onData(_onData);
}
void _onData(S data) {
if (_handleData == null) return;
T targetData = data as T;
_zone.runUnaryGuarded(_handleData, targetData);
}
複製程式碼
後記
至此,我們在Provider庫StreamProvider中遇到了Stream,我們在EventBus庫中遇到了Stream Dart語言自帶優秀的非同步程式設計模型 Stream和Future。 Stream擁有良好的非同步模型,滋養了一大波元件庫 Provider/BLoC/flutter_redux/Rxdart/fish-redux。 接下來就有必要對Stream進行分析了。