首页
Web开发
Windows程序
编程语言
数据库
移动开发
系统相关
微信
其他好文
会员
首页
>
其他好文
> 详细
otto源码分析
时间:
2015-08-28 13:40:04
阅读:
227
评论:
0
收藏:
0
[点我收藏+]
标签:
otto这个开源项目是一个event bus模式的消息框架,用于程序各个模块之间的通信,此消息框架可以使得各个
模块之间减少耦合性。
此项目是支付公司square一个开源项目,项目托管于github
https://github.com/square/otto
基本模型是,Android的组件可以注册监听,然后发送消息,接收消息,模式就是观察者模式,但是有别于
java实现的观察者模式,otto更具解耦性,通过注解可以现实监听工作。
otto中的总控制中心的类是Bus,复杂事件的注册分发工作。
首先要把需要把监听事件的组件或者发送事件的组件注册进去
调用Bus的register方法
public
void
register(Object object)
这个方法的解释是这样的,先看下英文
[html]
view plain
copy
/**
* Registers all handler methods on {@code object} to receive events and producer methods to provide events.
* If any subscribers are registering for types which already have a producer they will be called immediately
* with the result of calling that producer.
* If any producers are registering for types which already have subscribers, each subscriber will be called with
* the value from the result of calling the producer.
*
* @param object object whose handler methods should be registered.
* @throws NullPointerException if the object is null.
*/
参数这个对象的所有的事件处理方法(订阅方法)用于处理接受到的事件,生产者方法用于提供事件。
意思是说,这个注册者即可以接收事件,也可以生产事件。
接着说了注册时的一些特殊情况,
(1)如果在注册的时候,订阅了一个事件类型,并且有产生事件的方法,那么会立即调用产生事件的方法,
把事件分发给这个订阅者方法。
(2)如果在注册的时候,产生特定事件的方法已经存在了订阅者,会调用事件产生方法,把事件分发给事件
订阅者。
方法的具体实现分析:
[java]
view plain
copy
public
void
register(Object object) {
if
(object ==
null
) {
throw
new
NullPointerException(
"Object to register must not be null."
);
}
//检查是否在主线程中进行了注册的,默认必须在主线程中调用
enforcer.enforce(
this
);
//key是事件的class对象
Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);
上面的代码用于获取这个被注册对象的所有生产者方法,可以对应于多个事件的生产者方法
一个被注册对象,同一个事件只能注册一个生产者方法。
handlerFinder是HandlerFinder的实例,是Bus的辅助类,用于找到指定被注册者的所有生产者和订阅者方法。
handlerFinder
.findAllProducers(object)返回一个map集合,key是事件的Class的实例,value
是EventProducer是对生产者方法和被注册者实例的包装。
从这里可以看出,虽然没有继续看这个方法的代码,可以猜测被注册者对于同一个事件只能有一个生产者。
我们继续跟踪HandlerFinder
findAllProducers()方法的代码
HandlerFinder只是一个借口,然后在其内部实现了一个内部类
如下:
[java]
view plain
copy
HandlerFinder ANNOTATED =
new
HandlerFinder() {
@Override
public
Map<Class<?>, EventProducer> findAllProducers(Object listener) {
return
AnnotatedHandlerFinder.findAllProducers(listener);
}
@Override
public
Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener) {
return
AnnotatedHandlerFinder.findAllSubscribers(listener);
}
};
会调用到这句代码:
AnnotatedHandlerFinder.findAllProducers(listener)
进去看下代码
[java]
view plain
copy
static
Map<Class<?>, EventProducer> findAllProducers(Object listener) {
final
Class<?> listenerClass = listener.getClass();
Map<Class<?>, EventProducer> handlersInMethod =
new
HashMap<Class<?>, EventProducer>();
//检查是否不存在此listenerClass的生产者方法,需要找出来放到PRODUCERS_CACHE中
//PRODUCERS_CACHE是一个map,可以是listener的class对象,值是所有的事件生产者方法
if
(!PRODUCERS_CACHE.containsKey(listenerClass)) {
loadAnnotatedMethods(listenerClass);
}
//下面的代码就是把所有的生产者方法封装起来,返回给调用者
Map<Class<?>, Method> methods = PRODUCERS_CACHE.get(listenerClass);
if
(!methods.isEmpty()) {
for
(Map.Entry<Class<?>, Method> e : methods.entrySet()) {
EventProducer producer =
new
EventProducer(listener, e.getValue());
handlersInMethod.put(e.getKey(), producer);
}
}
return
handlersInMethod;
}
我们再回到Bus的register方法
[java]
view plain
copy
//key是事件的class对象
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);
}
}
}
这行代码用于回调
dispatchProducerResultToHandler(handler, producer);
具体实现就是通过反射去调用producer生产出方事件,把事件传递给handler,再通过反射
回调注册的方法。
继续。。。
[java]
view plain
copy
//如果有处理此事件的注册者,回调注册者
Map<Class<?>, Set<EventHandler>> foundHandlersMap = handlerFinder.findAllSubscribers(object);
for
(Class<?> type : foundHandlersMap.keySet()) {
//type变量是事件的class对象
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);
handlers.addAll(foundHandlers);
}
regeister这个方法解释完了。
在继续看下post(event)方法
这个方法的作用是分发事件到所有注册这个事件的方法
有可能这个事件分发失败,会封装一个DeadEvent对象,然后重新分发,但是这个DeadEvent对象没有被处理。。。
[java]
view plain
copy
public
void
post(Object event) {
if
(event ==
null
) {
throw
new
NullPointerException(
"Event to post must not be null."
);
}
enforcer.enforce(
this
);
//返回这个event的所有继承关系链的所有class对象(父类class对象和自己)
Set<Class<?>> dispatchTypes = flattenHierarchy(event.getClass());
//对event家族的所有类的相关注册方法进行调用
boolean
dispatched =
false
;
for
(Class<?> eventType : dispatchTypes) {
//获得和eventType相关的所有注册方法
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();
}
接下来就是注销方法unregister(listener)
删除和这个listener对象相关的生产事件的方法和注册监听的方法
[java]
view plain
copy
public
void
unregister(Object object) {
if
(object ==
null
) {
throw
new
NullPointerException(
"Object to unregister must not be null."
);
}
enforcer.enforce(
this
);
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()) {
//返回对应event的所有注册方法的包装类
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);
}
}
最后总结一下,
(1)同一个事件只能有一个生产此事件的方法,如果存在多个会报非检查异常,产生此类事件的只允许有一个来源或者说只允许
有一个活者的来源。
(2)同一个事件可以有多个注册监听同一个事件的方法,只要存在就会分发给他们。
(3)按照官方的demo尽量只有一个Bus实例,一是减少内存消耗,也利于分发工作,如果不同的Bus,那么就无法把分发给其他Bus的注册监听的方法了。
这个EventBus消息框架比较适合推送的处理中心对消息的分发工作,可以解耦的方式,分发给程序的各个模块。
otto源码分析
标签:
原文地址:http://my.oschina.net/owen123456/blog/498608
踩
(
0
)
赞
(
0
)
举报
评论
一句话评论(
0
)
登录后才能评论!
分享档案
更多>
2021年07月29日 (22)
2021年07月28日 (40)
2021年07月27日 (32)
2021年07月26日 (79)
2021年07月23日 (29)
2021年07月22日 (30)
2021年07月21日 (42)
2021年07月20日 (16)
2021年07月19日 (90)
2021年07月16日 (35)
周排行
更多
分布式事务
2021-07-29
OpenStack云平台命令行登录账户
2021-07-29
getLastRowNum()与getLastCellNum()/getPhysicalNumberOfRows()与getPhysicalNumberOfCells()
2021-07-29
【K8s概念】CSI 卷克隆
2021-07-29
vue3.0使用ant-design-vue进行按需加载原来这么简单
2021-07-29
stack栈
2021-07-29
抽奖动画 - 大转盘抽奖
2021-07-29
PPT写作技巧
2021-07-29
003-核心技术-IO模型-NIO-基于NIO群聊示例
2021-07-29
Bootstrap组件2
2021-07-29
友情链接
兰亭集智
国之画
百度统计
站长统计
阿里云
chrome插件
新版天听网
关于我们
-
联系我们
-
留言反馈
© 2014
mamicode.com
版权所有 联系我们:gaon5@hotmail.com
迷上了代码!