Otto 事件總線示例
Otto是釋出訂閱式架構。由Square開發,但是Square停止更新了,推薦用Rxjava來代替。還是來學習一下Otto的思想。
首先來看看示例,定義一個Otto管理類,封裝Bus的注冊、取消注冊,向外提供這些方法:
public class OttoBusManager {
private static OttoBusManager instance;
private Bus bus;
public static OttoBusManager getInstance() {
if (instance == null) {
synchronized (OttoBusManager.class) {
if (instance == null) {
instance = new OttoBusManager();
}
}
}
return instance;
}
private OttoBusManager() {
bus = new Bus(ThreadEnforcer.ANY);
}
public void register(Object o) {
bus.register(o);
}
public void unRegister(Object o) {
bus.unregister(o);
}
public void notifyNotification(User user){
bus.post(user);
}
}
然後再看看事件發送者如何使用:
//建立時注冊:
OttoBusManager.getInstance().register(this);
//銷毀時登出:
OttoBusManager.getInstance().unRegister(this);
//合适的地方發送通知:
OttoBusManager.getInstance().notifyNotification(new User());
//或者,給方法名添加注解
@Produce
Public BusData setInitialContent() {
return new BusData("更新資料了");
}
OttoBusManager.getInstance().notifyNotification(setInitialContent);
再看看消息接受者:
//在需要發送事件的地方,建立時注冊:
OttoBusManager.getInstance().register(this);
//銷毀時登出:
OttoBusManager.getInstance().unRegister(this);
//接受通知,接收通知的地方最好方法寫成一樣的,這樣比較好找,其實方法名可以任意的,區分是參數:
@Subscribe
public void notifyBatteryChange(BatteryInfoBus bus) {
//那麼隻要發送者發送了資料,接收者就可以收到了。
}
Otto源碼解析
可從三個步驟來分析:
1.register()
2.bus.post()
3.unregister()
1.register() 源碼
public void register(Object object) {
if (object == null) {
throw new NullPointerException("Object to register must not be null.");
}
//用于控制Bus的線程的,可以指定是any或者Main Thread
enforcer.enforce(this);
//用于找到Object類裡面标注了@Producer注解的方法,注意了,一個注冊類隻能有一個釋出者,但是可以有多個接收者。
Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);
for (Class<?> type : foundProducers.keySet()) {
final EventProducer producer = foundProducers.get(type);
EventProducer previousProducer = producersByType.putIfAbsent(type, producer);
//checking if the previous producer existed
if (previousProducer != null) {
throw new IllegalArgumentException("Producer method for type " + type
+ " found on type " + producer.target.getClass()
+ ", but already registered by type " + previousProducer.target.getClass() + ".");
}
Set<EventHandler> handlers = handlersByType.get(type);
if (handlers != null && !handlers.isEmpty()) {
for (EventHandler handler : handlers) {
dispatchProducerResultToHandler(handler, producer);
}
}
}
//一個注冊類可以有多個接受者,看Map的value,是一個Set集合就明白了。
Map<Class<?>, Set<EventHandler>> foundHandlersMap = handlerFinder.findAllSubscribers(object);
for (Class<?> type : foundHandlersMap.keySet()) {
Set<EventHandler> handlers = handlersByType.get(type);
if (handlers == null) {
//concurrent put if absent
Set<EventHandler> handlersCreation = new CopyOnWriteArraySet<EventHandler>();
handlers = handlersByType.putIfAbsent(type, handlersCreation);
if (handlers == null) {
handlers = handlersCreation;
}
}
final Set<EventHandler> foundHandlers = foundHandlersMap.get(type);
if (!handlers.addAll(foundHandlers)) {
throw new IllegalArgumentException("Object already registered.");
}
}
for (Map.Entry<Class<?>, Set<EventHandler>> entry : foundHandlersMap.entrySet()) {
Class<?> type = entry.getKey();
EventProducer producer = producersByType.get(type);
if (producer != null && producer.isValid()) {
Set<EventHandler> foundHandlers = entry.getValue();
for (EventHandler foundHandler : foundHandlers) {
if (!producer.isValid()) {
break;
}
if (foundHandler.isValid()) {
dispatchProducerResultToHandler(foundHandler, producer);
}
}
}
}
}
2.bus.post() 如何發送資料的過程。
public void post(Object event) {
if (event == null) {
throw new NullPointerException("Event to post must not be null.");
}
enforcer.enforce(this);
//找到訂閱了該事件的所有class。
Set<Class<?>> dispatchTypes = flattenHierarchy(event.getClass());
boolean dispatched = false;
for (Class<?> eventType : dispatchTypes) {
//周遊該class集合,找到對應的注冊了該事件的方法,
Set<EventHandler> wrappers = getHandlersForEventType(eventType);
if (wrappers != null && !wrappers.isEmpty()) {
dispatched = true;
for (EventHandler wrapper : wrappers) {
//将這些訂閱了該事件的方法放入隊列中
enqueueEvent(event, wrapper);
}
}
}
if (!dispatched && !(event instanceof DeadEvent)) {
post(new DeadEvent(this, event));
}
//從隊列中取出訂閱了該事件的方法
dispatchQueuedEvents();
}
3. 取消注冊
public void unregister(Object object) {
if (object == null) {
throw new NullPointerException("Object to unregister must not be null.");
}
enforcer.enforce(this);
//取消釋出者,從緩存中拿到指定釋出者,然後remove掉
Map<Class<?>, EventProducer> producersInListener = handlerFinder.findAllProducers(object);
for (Map.Entry<Class<?>, EventProducer> entry : producersInListener.entrySet()) {
final Class<?> key = entry.getKey();
EventProducer producer = getProducerForEventType(key);
EventProducer value = entry.getValue();
if (value == null || !value.equals(producer)) {
throw new IllegalArgumentException(
"Missing event producer for an annotated method. Is " + object.getClass()
+ " registered?");
}
producersByType.remove(key).invalidate();
}
//取消訂閱者,方法一樣。
Map<Class<?>, Set<EventHandler>> handlersInListener = handlerFinder.findAllSubscribers(object);
for (Map.Entry<Class<?>, Set<EventHandler>> entry : handlersInListener.entrySet()) {
Set<EventHandler> currentHandlers = getHandlersForEventType(entry.getKey());
Collection<EventHandler> eventMethodsInListener = entry.getValue();
if (currentHandlers == null || !currentHandlers.containsAll(eventMethodsInListener)) {
throw new IllegalArgumentException(
"Missing event handler for an annotated method. Is " + object.getClass()
+ " registered?");
}
for (EventHandler handler : currentHandlers) {
if (eventMethodsInListener.contains(handler)) {
handler.invalidate();
}
}
currentHandlers.removeAll(eventMethodsInListener);
}
}
這個架構其實很簡單,将接受者注冊到一個Map中,當發送者發送消息時,周遊Map,找到具體的接受者,然後調用它的接受方法即可。