EventBus源码分析

来源:互联网 发布:notepad 和python 编辑:程序博客网 时间:2024/05/29 09:23

    <h2 id="EventBus简介"><a href="#EventBus简介" class="headerlink" title="EventBus简介"></a>EventBus简介</h2><p>本篇基于EventBus 2.4撰写。</p>

Android optimized event bus that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality.

上面是从官方repo拉来的代码,大致是说简化的组件之间的交流通信,减少代码,提高质量。

其实和EventBus最早是在qzone的代码里认识的,空间内部有一个叫eventcenter的东西,曾经有优化过一些,当时看源码实现的时候发现的原来是根据EventBus改的一个实现。大概就是把annotation的实现改成了接口实现,另外去掉了根据Event类型来找订阅者的模式,完全通过Event的TYPE类型常量来判断,register的时候直接指定对哪种TYPE感兴趣,辅助的判断则有事件发送者引用。这种实现见仁见智吧,虽然直接通过接口肯定是能提高性能的。这里要吐槽的是实现修改的时候,直接把很多对外的接口名字改掉了,何必呢。

EventBus的好处是显而易见的,完全解耦了请求链之间的关系,避免了请求者被长持有,又比广播更轻量,比LocalBroadcast则更强大,接口也简单实用。缺点的话,像是各种Event的定义是一个工作量。

源码分析 - 注册(register)

EventBus.java:

1
2
3
4
5
6
private synchronized void register(Object subscriber, boolean sticky, int priority) {
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod, sticky, priority);
}
}

register的时候,大致就是去subscriber里面首先找到那些onEvent方法(目前实现仍然是根据onEvent这个前缀),寻找的时候会去判断后缀,分为post线程、主线程、background线程,以及异步线程,官方repo提到这里之后在3.0可能会换成annotation的实现。

sticky参数是粘性事件概念,postSticky和registerSticky相对应,stickyEvent会记录该EventType对应的最后一次postSticky的事件,这样在registerSticky的时候,会立即检查是否有之前post的事件,从而避免了某些事件去实现自己的缓存。应用场景大概就是某些activity/fragment感兴趣的事件发生在创建前,这样则可以避免必须实现缓存(当然事实上应用场景还是比较少的,因为大部分东西我们还是会在哪里记录一下)

SubscriberMethod.java:

1
2
3
4
5
6
7
final class SubscriberMethod {
final Method method;
final ThreadMode threadMode;
final Class<?> eventType;
/** Used for efficient comparison */
String methodString;
}

SubscriberMethod里面记录了Method引用,线程模式(在findSubscriberMethods里拿到的),eventType,以及用来提高method.equals性能的methodString。

接着再看subscribe方法的实现,在register最后,对找到的所有方法都去执行了一遍subscribe
EventBus.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {
Class<?> eventType = subscriberMethod.eventType;
// CopyOnWriteArrayList就是个ImmutableArrayList, add/set等方法会返回一个新的ArrayList
// subscriptionsByEventType是一个hashmap,key是事件类型,value则是订阅者数组
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);
// 该eventType在map里还不存在,新建一下对应的subscription数组,放进去map
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<Subscription>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
// 重复注册的时候抛出异常,这里如果应用如果觉得无伤大雅其实可以直接return
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
// 根据优先级去添加到对应的位置,高优先级在前面也就会先处理
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || newSubscription.priority > subscriptions.get(i).priority) {
subscriptions.add(i, newSubscription);
break;
}
}
// typesBySubscriber是另一个map,顾名思义是以subscriber为key的一个map,被用在
// 1) isRegistered(Object subscriber)方法加速判断是否已注册,用空间换时间
// 2) unregister的时候直接可以拿到subscriber订阅的所有eventType,然后去从map移除,避免需要遍历所有eventType的map
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<Class<?>>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
// 粘性事件的话,就去立刻找一下是否有之前post过的事件,有则立即post给该subscriber
if (sticky) {
if (eventInheritance) {
// Existing sticky events of all subclasses of eventType have to be considered.
// Note: Iterating over all events may be inefficient with lots of sticky events,
// thus data structure should be changed to allow a more efficient lookup
// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}

源码分析 - 发送事件(post)

再来看一下对应的post逻辑

EventBus.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/** Posts the given event to the event bus. */
public void post(Object event) {
// 获得当前post线程的状态,实现贴在下面了,currentPostingThreadState是ThreadLocal<PostingThreadState>变量,每个线程get和set的都是单独的一份数据
PostingThreadState postingState = currentPostingThreadState.get();
// 往事件队列里面添加该event
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
// 如果当前不在posting事件
if (!postingState.isPosting) {
// 设置是否在主线程
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
// 设置当前正在post事件
postingState.isPosting = true;
// canceled状态,抛出异常
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
// 循环post从eventQueue里面拿出来的event
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
// 置位回去
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<Object>();
boolean isPosting;
boolean isMainThread;
Subscription subscription;
Object event;
// 可以通过cancelEventDelivery去取消事件传递
boolean canceled;
}
// 单个事件的post处理
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
// 继承链处理,比如Event本身的父类的subscriber也会收到,getDefault的时候默认为true。
if (eventInheritance) {
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
// 竟然没找到,太诡异了
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
// 没想到还有这种逻辑吧,没找到订阅者的,则会发送一个NoSubscriberEvent出去
post(new NoSubscriberEvent(this, event));
}
}
}
// 对特定的event去post单个事件
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
// 找到该事件的所有订阅
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
// 遍历所有订阅
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
// 结果实际post还在这个方法内实现
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
// 如果cancel了,则不再继续传递事件
if (aborted) {
break;
}
}
return true;
}
return false;
}
// 具体的事件分发
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
// 这里就是EventBus的一个很强大的功能了,根据订阅者的订阅方法监听线程去处理
// 如果post和监听方法在同一个线程则立即invoke对应方法
// 否则会去入队列到对应线程handler进行处理
switch (subscription.subscriberMethod.threadMode) {
case PostThread:
invokeSubscriber(subscription, event);
break;
case MainThread:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case BackgroundThread:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case Async:
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}

End

大致就讲了一下register和post这一对比较常用的接口,其他还有一些实现像是EventBusBuilder,SubscriberException,cancelEventDelivery,AsyncExecutor就不在这里进行赘述,之后可能会对AsyncExecutor单独开一篇讲一下,另外也会对otto的实现做一下分析。

转自:http://blog.zhaiyifan.cn/2015/08/20/EventBus-source/

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 菜刀划到手指怎么办 商标被异议了怎么办 眉毛没有绣好怎么办 一点眉毛都没有怎么办 山根一点都没有怎么办 深眼窝怎么办怎么恢复 下眼睑皱纹严重怎么办 下眼睑有皱纹怎么办 额头上有皱纹怎么办 额头有八字纹怎么办 脸上有八字纹怎么办 脸上皱纹多怎么办呢 颧骨太高了怎么办 戴眼镜颧骨突出怎么办 额窦炎引起头晕怎么办 额窦炎引起头痛怎么办 额窦炎头痛头晕怎么办 急性额窦炎头疼怎么办 上额窦炎头疼怎么办 宿醉第二天头疼怎么办 眉骨高低不一样怎么办 额头两边凹进去怎么办 眼角下垂,眼睛小怎么办 眉毛眼睛距离大怎么办 眉毛眼睛距离远怎么办 眼睛眉毛距离远怎么办 眉毛离眼睛远怎么办 额头上长猴子怎么办 额头上长瘊子怎么办 眉毛看起来很凶怎么办 眉毛很少很淡怎么办 眉毛太少了怎么办 眉毛淡又少怎么办 额头皱纹很深怎么办 我抬头纹很重怎么办 22岁抬头纹严重怎么办 眼睛没有卧蚕怎么办 眼袋把卧蚕遮了怎么办 小孩子的眉毛淡怎么办 自己不会修眉毛怎么办 老婆性格太强势怎么办