源碼目錄:
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
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2Lc5WNyImcWdVW6hmMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2LcRHelR3LcJzLctmch1mclRXY39jM1kzMwQTN1EjNycDM4EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
第二步,訂閱事件。訂閱者需要定義事件處理方法(也稱為訂閱者方法)。當釋出對應類型的事件時,該方法将被調用。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<Class<? extends Object>, ArrayList<EventHandlerMethod>> mSubscriberTypeMap = new HashMap<>();
private HashMap<Class<? extends Event>, ArrayList<EventHandler>> mEventTypeMap = new HashMap<>();
private ArrayList<Subscriber> mSubscribers = new ArrayList<>();//儲存已經注冊的訂閱者數組清單
//訂閱事件(注冊)
private void registerSubscriber(Object subscriber, int priority,
MutableBoolean hasInterprocessEventsChangedOut) {
...
if (findRegisteredSubscriber(subscriber, false )) {//判斷目前的訂閱者是否已經注冊過
return;
}
...
Subscriber sub = new Subscriber(subscriber, SystemClock.uptimeMillis());//對訂閱者進行封裝
Class<?> subscriberType = subscriber.getClass();//擷取訂閱者的類型類
ArrayList<EventHandlerMethod> subscriberMethods = mSubscriberTypeMap.get(subscriberType);//以訂閱者類型類為鍵值
//來查詢映射表是否有相應的事件句柄方法數組
if (subscriberMethods != null) {//映射表存在
for (EventHandlerMethod method : subscriberMethods) {
ArrayList<EventHandler> eventTypeHandlers = mEventTypeMap.get(method.eventType);//查詢哈希表中知道事件類型的事件句柄數組
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;
if (isValidEventBusHandlerMethod(m, parameterTypes, isInterprocessEvent)) {//是有效的訂閱者方法
Class<? extends Event> eventType = (Class<? extends Event>) parameterTypes[0];
ArrayList<EventHandler> eventTypeHandlers = mEventTypeMap.get(eventType);//查找哈希表中以此方法參數事件類型為鍵值的事件句柄數組
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 )) {/判斷目前的訂閱者是否已經注冊過
return;
}
Class<?> subscriberType = subscriber.getClass();
ArrayList<EventHandlerMethod> subscriberMethods = mSubscriberTypeMap.get(subscriberType);//查找哈希表擷取事件句柄方法數組
if (subscriberMethods != null) {
// For each of the event handlers the subscriber handles, remove all references of that
// handler
for (EventHandlerMethod method : subscriberMethods) {
ArrayList<EventHandler> eventHandlers = mEventTypeMap.get(method.eventType);//查找哈希表擷取事件句柄數組
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<EventHandler> eventHandlers = mEventTypeMap.get(event.getClass());//查找哈希表擷取事件句柄數組
if (eventHandlers == null) {
event.onPreDispatch();
event.onPostDispatch();
return;
}
boolean hasPostedEvent = false;
event.onPreDispatch();//訂閱者方法執行前執行的方法
eventHandlers = (ArrayList<EventHandler>) eventHandlers.clone();//克隆一個哈希表數組
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());
}
}