源码目录:
EventBus.java:\frameworks\base\packages\SystemUI\src\com\android\systemui\recents\events\EventBus.java
参考文章链接:
EventBus使用详解:https://blog.csdn.net/u012317510/article/details/78935720
Android多窗口框架全解析:https://blog.csdn.net/xiaosayidao/article/details/75045087
一、前言
最近在分析android O的多窗口框架源码时,在分析设置栈边界的源码时,遇见EventBus.getDefault().send(new DockedTopTaskEvent(dragMode, initialBounds))时不太明白,随即去百度一下EventBus的功能,并研究了EventBus的源码,学习其设计理论。
EventBus是一种用于Android的发布/订阅事件总线。它有很多优点:简化应用组件间的通信;解耦事件的发送者和接收者;避免复杂和容易出错的依赖和生命周期的问题;很快,专门为高性能优化过等等。
二、基本使用
EventBus的使用非常简单,主要分为3个步骤:
第一步,定义事件。事件可以是继承EventBus.Event的任意普通的java对象,没有任何特殊要求。例如:
源码目录:\frameworks\base\packages\SystemUI\src\com\android\systemui\recents\events\activity\DockedTopTaskEvent.java
第二步,订阅事件。订阅者需要定义事件处理方法(也称为订阅者方法)。当发布对应类型的事件时,该方法将被调用。EventBus的订阅者需要有方法名是以”onBusEvent”或者“onInterprocessBusEvent”字符串开头的方法来作为订阅者方法,参数类型为订阅事件的类型。例如:
源码目录:frameworks\base\packages\systemui\src\com\android\systemui\stackdivider\DividerView.java
订阅者还需要再总线上注册,并在不需要时在总线上注销。只有订阅者注册了,它们才会收到事件。在Android中,可以根据Activity或者Fragment的生命周期来注册和注销,也可以根据FrameLayout的附加到窗口及从窗口上分离的方法来注册和注销,例如:
第三步,发布事件。在需要的地方发布事件,所有订阅了该类型事件并已注册的订阅者将收到该事件。例如:
在分屏模式设置栈边界通过发送消息的一个机制让订阅者实现相关功能
EventBus.getDefault().send(new DockedTopTaskEvent(dragMode, initialBounds));
三、EventBus源码分析
源码目录:\frameworks\base\packages\SystemUI\src\com\android\systemui\recents\events\EventBus.java
/**
*以订阅者的类型类为键值,事件句柄方法数组列表为映射值来保存哈希表
**/
private HashMap
/**
*以事件类型(也就是订阅者方法参数类型)为键值,事件句柄数组列表为映射值来保存哈希表
**/
private HashMap
private ArrayList
//订阅事件(注册)
private void registerSubscriber(Object subscriber, int priority,
MutableBoolean hasInterprocessEventsChangedOut) {
...
if (findRegisteredSubscriber(subscriber, false /* removeFoundSubscriber */)) {//判断当前的订阅者是否已经注册过
return;
}
...
Subscriber sub = new Subscriber(subscriber, SystemClock.uptimeMillis());//对订阅者进行封装
Class> subscriberType = subscriber.getClass();//获取订阅者的类型类
ArrayList
//来查询映射表是否有相应的事件句柄方法数组
if (subscriberMethods != null) {//映射表存在
for (EventHandlerMethod method : subscriberMethods) {
ArrayList
eventTypeHandlers.add(new EventHandler(sub, method, priority));//向事件句柄数组添加新的事件句柄
sortEventHandlersByPriority(eventTypeHandlers);//按优先级进行排序
}
mSubscribers.add(sub);//保存当前注册的订阅者到数组中
return;
} else {//不存在
subscriberMethods = new ArrayList<>();//创建事件句柄方法数组
mSubscriberTypeMap.put(subscriberType, subscriberMethods);//保存到映射表
mSubscribers.add(sub);//保存当前注册的订阅者到数组中
}
// Find all the valid event bus handler methods of the subscriber
MutableBoolean isInterprocessEvent = new MutableBoolean(false);
Method[] methods = subscriberType.getDeclaredMethods();//获取订阅者类的所有方法
for (Method m : methods) {
Class>[] parameterTypes = m.getParameterTypes();//获取m对象表示的方法的形式参数类型
isInterprocessEvent.value = false;
/**
*用于判断此方法是否是订阅者方法,通过分析此方法可以知道,订阅者方法必现是public final void类型的,
*且方法的第一个参数必现是EventBus.Event子类,且方法名必现以字符串"onBusEvent"或者"onInterprocessBusEvent"开头
**/
if (isValidEventBusHandlerMethod(m, parameterTypes, isInterprocessEvent)) {//是有效的订阅者方法
Class extends Event> eventType = (Class extends Event>) parameterTypes[0];
ArrayList
if (eventTypeHandlers == null) {//如果没有找到,则新建句柄数组,并添加到哈希表中
eventTypeHandlers = new ArrayList<>();
mEventTypeMap.put(eventType, eventTypeHandlers);
}
if (isInterprocessEvent.value) {//以"onInterprocessBusEvent"字符串开头的订阅者方法需要做的一些处理,这边暂时不分析了
try {
// Enforce that the event must have a Bundle constructor
eventType.getConstructor(Bundle.class);
mInterprocessEventNameMap.put(eventType.getName(),
(Class extends InterprocessEvent>) eventType);
if (hasInterprocessEventsChangedOut != null) {
hasInterprocessEventsChangedOut.value = true;
}
} catch (NoSuchMethodException e) {
throw new RuntimeException("Expected InterprocessEvent to have a Bundle constructor");
}
}
EventHandlerMethod method = new EventHandlerMethod(m, eventType);//以m方法及m方法参数为参数新建EventHandlerMethod事件句柄方法对象
EventHandler handler = new EventHandler(sub, method, priority);//以订阅者及事件句柄方法及优先级为参数新建EventHandler事件句柄对象
eventTypeHandlers.add(handler);//添加到事件句柄数组中,这样可以在mEventTypeMap哈希表中通过事件类型(也就是订阅者方法参数)为键值查找
subscriberMethods.add(method);//添加到事件句柄方法数组中,这样可以在mSubscriberTypeMap哈希表中通过订阅者的类型类为键值来查找
sortEventHandlersByPriority(eventTypeHandlers);//按优先级进行排序
...
}
}
...
}
//取消事件订阅(反注册)
public void unregister(Object subscriber) {
...
if (!findRegisteredSubscriber(subscriber, true /* removeFoundSubscriber */)) {/判断当前的订阅者是否已经注册过
return;
}
Class> subscriberType = subscriber.getClass();
ArrayList
if (subscriberMethods != null) {
// For each of the event handlers the subscriber handles, remove all references of that
// handler
for (EventHandlerMethod method : subscriberMethods) {
ArrayList
for (int i = eventHandlers.size() - 1; i >= 0; i--) {
if (eventHandlers.get(i).subscriber.getReference() == subscriber) {
eventHandlers.remove(i);//从事件句柄数组中删除
}
}
}
}
}
//事件发布
发布事件
public void send(Event event) {
...
event.requiresPost = false;
event.cancelled = false;
queueEvent(event);
}
private void queueEvent(final Event event) {
ArrayList
if (eventHandlers == null) {
event.onPreDispatch();
event.onPostDispatch();
return;
}
boolean hasPostedEvent = false;
event.onPreDispatch();//订阅者方法执行前执行的方法
eventHandlers = (ArrayList
int eventHandlerCount = eventHandlers.size();
for (int i = 0; i < eventHandlerCount; i++) {
final EventHandler eventHandler = eventHandlers.get(i);
if (eventHandler.subscriber.getReference() != null) {
if (event.requiresPost) {
mHandler.post(new Runnable() {
@Override
public void run() {
processEvent(eventHandler, event);
}
});
hasPostedEvent = true;
} else {
processEvent(eventHandler, event);//订阅者方法在此方法内执行
}
}
}
if (hasPostedEvent) {
mHandler.post(new Runnable() {
@Override
public void run() {
event.onPostDispatch();
}
});
} else {
event.onPostDispatch();//订阅者方法执行完成后执行的方法
}
}
private void processEvent(final EventHandler eventHandler, final Event event) {
...
try {
...
Object sub = eventHandler.subscriber.getReference();//获取订阅者对象
if (sub != null) {
long t1 = 0;
if (DEBUG_TRACE_ALL) {
t1 = SystemClock.currentTimeMicro();
}
eventHandler.method.invoke(sub, event);//通过反射调用订阅者方法
if (DEBUG_TRACE_ALL) {
long duration = (SystemClock.currentTimeMicro() - t1);
mCallDurationMicros += duration;
mCallCount++;
logWithPid(eventHandler.method.toString() + " duration: " + duration +
" microseconds, avg: " + (mCallDurationMicros / mCallCount));
}
} else {
Log.e(TAG, "Failed to deliver event to null subscriber");
}
} catch (IllegalAccessException e) {
Log.e(TAG, "Failed to invoke method", e.getCause());
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getCause());
}
}