EventBus原理
- 訂閱邏輯
register註冊訂閱者
反射遍歷訂閱者的方法
通過訂閱註解從訂閱者中獲取訂閱事件響應方法的資訊
向訂閱該事件型別的訂閱者集合中新增該訂閱者
向該訂閱者所訂閱的事件型別集合中新增該事件型別 - 事件分發邏輯
將事件新增到ThreadLocal中的MessageQueue
根據事件型別獲取所有訂閱者
事件分發給訂閱時指定對應的處理執行緒
遍歷反射呼叫事件響應響應方法 - 取消訂閱邏輯
根據該訂閱者獲取所有訂閱事件型別
遍歷根據事件型別將訂閱該事件型別的訂閱者集合中刪除該訂閱者
從map中刪除該訂閱者和它訂閱的事件型別集合
動手實現EventBus
只是實現向在主執行緒處理訊息傳送的事件。通過Handler來做非同步通訊的基礎元件,分發處理訊息。
- 事件分發邏輯
將事件物件包裝為message通過handler新增到主執行緒的MessageQueue
Looper從messageQueue分發事件觸發handleMessage方法
在handleMessage()中根據事件型別找到所有訂閱該事件型別的訂閱資訊
遍歷反射呼叫這些響應該事件型別的方法
public class EventBus {
private volatile static EventBus defaultInstance;
private static Map<Object, List<Object>> subscribeEventsMap = new HashMap<>();//訂閱者-事件型別集合
private static Map<Object, List<SubscribeInfo>> eventSubscribesMap = new HashMap<>();//事件型別-訂閱資訊集合
private Handler handler;//非同步通訊元件
private EventBus() {
//初始化handler基礎元件來處理事件
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Class eventType = msg.obj.getClass();
//獲取訂閱該事件型別的訂閱資訊集合
List<SubscribeInfo> subscribeInfos = eventSubscribesMap.get(eventType);
if (subscribeInfos == null || subscribeInfos.size() != 0) return;
try {
for (SubscribeInfo item : subscribeInfos) {//迴圈訂閱資訊
//反射呼叫訂閱的響應函式
item.method.invoke(item.subscriber, msg.obj);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
};
}
/**
* 懶漢double check單例實現
*
* @return
*/
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
/**
* 註冊訂閱者
*
* @param subscriber
*/
public void register(Object subscriber) {
Method[] declaredMethods = subscriber.getClass().getDeclaredMethods();
//獲取訂閱者訂閱的事件型別集合
List<Object> events = getEventsBySubscriber(subscriber);
//從訂閱者的函式中找到處理事件的響應函式
for (Method item : declaredMethods) {
Subscribe annotation = item.getAnnotation(Subscribe.class);
//通過訂閱註解來判斷是否是使用者訂閱的響應函式
if (annotation != null) {
Class<?>[] parameterTypes = item.getParameterTypes();
if (parameterTypes.length != 1) {
throw new IllegalArgumentException("subscribe event must have ont event object!");
}
Class eventType = parameterTypes[0];
events.add(eventType);//新增到該訂閱事件集合中
SubscribeInfo info = new SubscribeInfo();
info.subscriber = subscriber;
info.eventType = eventType;
info.method = item;//記錄方法物件,加快反射呼叫方法速率
//獲取訂閱事件型別的那些訂閱資訊集合
List<SubscribeInfo> subscribeInfos = getSubscribeInfosByEvent(eventType);
subscribeInfos.add(info);//新增到對該事件的訂閱資訊集合中
}
}
}
/**
* 通過訂閱者獲取訂閱的事件型別集合
*
* @param subscriber
* @return
*/
private List<Object> getEventsBySubscriber(Object subscriber) {
List<Object> events = null;
if (subscribeEventsMap.containsKey(subscriber)) {
events = subscribeEventsMap.get(subscriber);
} else {
events = new ArrayList<>();
subscribeEventsMap.put(subscriber, events);
}
return events;
}
/**
* 通過事件型別獲取所有訂閱它的訂閱資訊
*
* @param eventType
* @return
*/
private static List<SubscribeInfo> getSubscribeInfosByEvent(Class eventType) {
List<SubscribeInfo> subscribeInfos = null;
if (eventSubscribesMap.containsKey(eventType)) {
eventSubscribesMap.get(eventType);
} else {
subscribeInfos = new ArrayList<>();
eventSubscribesMap.put(eventType, subscribeInfos);
}
return subscribeInfos;
}
/**
* 取消訂閱者
*
* @param subscriber
*/
public void unregister(Object subscriber) {
Object eventType = subscribeEventsMap.get(subscriber);
if (eventType == null) return;
eventSubscribesMap.remove(eventType);
subscribeEventsMap.remove(subscriber);
}
/**
* 傳送訊息
* @param event
*/
public void post(Object event) {
Message message = handler.obtainMessage();
message.obj = event;
handler.sendMessage(message);
}
/**
* 延遲傳送訊息
* @param event
* @param delayMillis
*/
public void postDelay(Object event, long delayMillis) {
Message message = handler.obtainMessage();
message.obj = event;
handler.sendMessageDelayed(message, delayMillis);
}
/**
* 訂閱資訊:記錄訂閱者的事件響應函式的資訊
*/
class SubscribeInfo {
Object subscriber;//訂閱者
Object eventType;//事件型別
Method method;//響應函式
}
}
複製程式碼
Subscribe.java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface HSubscribe {
}
複製程式碼
使用
....
EventBus.getDefault().register(this);//註冊訂閱者
....
//訂閱事件響應方法
@Subscribe
public void onComputeEvent(PublishFragment.ComputeEvent event) {
tvContent.setText(event.value + "");
}
=============
....
ComputeEvent event = new ComputeEvent();
event.value = value;
EventBus.getDefault().post(event);//傳送事件
....
//事件型別定義
public class ComputeEvent {
public int value;
}
複製程式碼