EventBus原理解析,純手工帶你擼代碼實(shí)現(xiàn)EventBus框架

github源碼分享:https://github.com/greenrobot/EventBus

官方圖解:

EventBus是Android和Java的發(fā)布/訂閱事件總線。

EventBus優(yōu)勢(shì):

1、簡(jiǎn)化了組件之間的通信:

將事件發(fā)送者和接收者分離

在活動(dòng),片段和后臺(tái)線程中表現(xiàn)良好

避免復(fù)雜且容易出錯(cuò)的依賴(lài)關(guān)系和生命周期問(wèn)題

2、使您的代碼更簡(jiǎn)潔

3、很快

4、很?。s50kb)

5、已經(jīng)通過(guò)100,000,000+安裝的應(yīng)用程序在實(shí)踐中得到證實(shí)

6、具有交付線程,用戶(hù)優(yōu)先級(jí)等高級(jí)功能;

總結(jié):

EventBus的使用比較簡(jiǎn)單,可以按照官網(wǎng)圖的方式來(lái)進(jìn)行理解。EventBus相當(dāng)于郵箱,發(fā)布者直接把信息放到信箱,信箱會(huì)自動(dòng)把信息發(fā)給訂閱了的人。

這里簡(jiǎn)單梳理一下EventBus的主要邏輯:

1、EventBus對(duì)象的構(gòu)建,使用單列模式創(chuàng)建

2、注冊(cè)事件,包含粘性事件

3、發(fā)布消息

4、接受消息

5、反注冊(cè)事件,避免內(nèi)存泄漏

(一)、EventBus構(gòu)造方法原理


這里就簡(jiǎn)單的使用單例模式實(shí)現(xiàn)

EventBus.java

private static EventBus instance;

public static EventBus getDefault() {

? ? if (instance == null) {

? ? ? ? synchronized (EventBus.class) {

? ? ? ? ? ? if (instance == null) {

? ? ? ? ? ? ? ? instance = new EventBus();

? ? ? ? ? ? }

? ? ? ? }

? ? }

? ? return instance;

}

(二)、注冊(cè)事件


注冊(cè)就是將此類(lèi)中的所有的帶Subscriber注解的方法緩存起來(lái),以便發(fā)布消息時(shí)調(diào)用;

我們也是簡(jiǎn)單的模擬實(shí)現(xiàn)注冊(cè),不包含粘性事件的注冊(cè)

需求:從AActivity跳轉(zhuǎn)到BActivity中,在BActivity中發(fā)布消息給AActivity;

//比如在AActivity接受事件,我們就在AActivity中注冊(cè)一個(gè)接收消息的方法

如:

MainActivity.java

@Override

protected void onCreate(Bundle savedInstanceState) {

? ? super.onCreate(savedInstanceState);

? ? setContentView(R.layout.activity_main);

? //注冊(cè)

? ? EventBus.getDefault().register(this);

}

@Subscribe(threadMode = ThreadMode.BACKGROUND)

public void handleMessages(EventBean eventBean) {

? ? Log.d("======>", eventBean.toString());

? ? Log.d("======", "send: MainActivity " + Thread.currentThread().getName());

}

Subscribe是一個(gè)注解類(lèi),用來(lái)標(biāo)記一個(gè)方法

Subscribe.java

@Documented

@Retention(RetentionPolicy.RUNTIME)// 表示為運(yùn)行時(shí)注解

@Target({ElementType.METHOD})

public @interface Subscribe {

? ? // 指定事件訂閱方法的線程模式,即在那個(gè)線程執(zhí)行事件訂閱方法處理事件,默認(rèn)為POSTING

? ? ThreadMode threadMode() default ThreadMode.POSTING;

? ? // 是否支持粘性事件,默認(rèn)為false

? ? boolean sticky() default false;

? ? // 指定事件訂閱方法的優(yōu)先級(jí),默認(rèn)為0,如果多個(gè)事件訂閱方法可以接收相同事件的,則優(yōu)先級(jí)高的先接收到事件

? ? int priority() default 0;

}

ThreadMode是一個(gè)枚舉類(lèi),用來(lái)標(biāo)記此方法在那個(gè)線程執(zhí)行

ThreadMode.java

public enum ThreadMode {

? ? POSTING,//默認(rèn)的線程模式,在那個(gè)線程發(fā)送事件就在對(duì)應(yīng)線程處理事件,避免了線程切換,效率高。

? ? MAIN,//如在主線程(UI線程)發(fā)送事件,則直接在主線程處理事件;如果在子線程發(fā)送事件,則先將事件入隊(duì)列,然后通過(guò) Handler 切換到主線程,依次處理事件。

? ? MAIN_ORDERED,//無(wú)論在那個(gè)線程發(fā)送事件,都先將事件入隊(duì)列,然后通過(guò) Handler 切換到主線程,依次處理事件。

? ? BACKGROUND,//如果在主線程發(fā)送事件,則先將事件入隊(duì)列,然后通過(guò)線程池依次處理事件;如果在子線程發(fā)送事件,則直接在發(fā)送事件的線程處理事件。

? ? ASYNC//無(wú)論在那個(gè)線程發(fā)送事件,都將事件入隊(duì)列,然后通過(guò)線程池處理。

}

private Map<Object, List<SubscriberMethod>> cacheMap;// 用來(lái)緩存注冊(cè)\訂閱的事件

public void register(Object subscriber) {

? ? // 檢查此類(lèi)是否已經(jīng)注冊(cè)

? ? List<SubscriberMethod> subscriberMethods = cacheMap.get(subscriber);

? ? if (subscriberMethods == null) {

? ? ? ? subscriberMethods = findSubscriberMethods(subscriber);

? ? ? ? cacheMap.put(subscriber, subscriberMethods);

? ? }

}

/**

* 查找此類(lèi)以及父類(lèi)中所有帶Subscriber注釋的方法

* @param subscriber

* @return

*/

private List<SubscriberMethod> findSubscriberMethods(Object subscriber) {

? ? List<SubscriberMethod> list = new ArrayList<>();

? ? Class<?> clazz = subscriber.getClass();

? ? while (clazz != null) {

? ? ? ? String name = clazz.getName();

? ? ? ? // 過(guò)濾系統(tǒng)類(lèi)

? ? ? ? if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {

? ? ? ? ? ? break;

? ? ? ? }

? ? ? ? Method[] methods = clazz.getDeclaredMethods();// 獲取此類(lèi)中所有的的方法(包含繼承父類(lèi)中的)

? ? ? ? for (Method method : methods) {

? ? ? ? ? ? Subscribe annotation = method.getAnnotation(Subscribe.class);// 找到方法上的注解參數(shù)

? ? ? ? ? ? if (annotation == null) {

? ? ? ? ? ? ? ? continue;

? ? ? ? ? ? }

? ? ? ? ? ? //獲取所有帶有Subscribe注解的方法中的參數(shù)類(lèi)型

? ? ? ? ? ? Class<?>[] parameterTypes = method.getParameterTypes();

? ? ? ? ? ? if (parameterTypes.length != 1) {// 只記錄帶有一個(gè)參數(shù)的方法

? ? ? ? ? ? ? ? Log.e("error", "EventBus only support one para");

? ? ? ? ? ? ? ? continue;

? ? ? ? ? ? }

? ? ? ? ? ? ThreadMode threadMode = annotation.threadMode();

? ? ? ? ? ? SubscriberMethod subscriberMethod = new SubscriberMethod(method, parameterTypes[0], threadMode, 0, false);

? ? ? ? ? ? list.add(subscriberMethod);

? ? ? ? }

? ? ? ? clazz = clazz.getSuperclass();

? ? }

? ? return list;

}

SubscriberMethod.java 帶有注解的方法對(duì)象

public class SubscriberMethod {

? ? private Method method;

? ? private ThreadMode threadMode;

? ? private Class<?> eventType;

? ? private int priority;

? ? private boolean sticky;

? ? /**

? ? * Used for efficient comparison

? ? */

? ? String methodString;

? ? public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {

? ? ? ? this.method = method;

? ? ? ? this.threadMode = threadMode;

? ? ? ? this.eventType = eventType;

? ? ? ? this.priority = priority;

? ? ? ? this.sticky = sticky;

? ? }

? ? @Override

? ? public boolean equals(Object other) {

? ? ? ? if (other == this) {

? ? ? ? ? ? return true;

? ? ? ? } else if (other instanceof SubscriberMethod) {

? ? ? ? ? ? checkMethodString();

? ? ? ? ? ? SubscriberMethod otherSubscriberMethod = (SubscriberMethod) other;

? ? ? ? ? ? otherSubscriberMethod.checkMethodString();

? ? ? ? ? ? // Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c6

? ? ? ? ? ? return methodString.equals(otherSubscriberMethod.methodString);

? ? ? ? } else {

? ? ? ? ? ? return false;

? ? ? ? }

? ? }

? ? private synchronized void checkMethodString() {

? ? ? ? if (methodString == null) {

? ? ? ? ? ? // Method.toString has more overhead, just take relevant parts of the method

? ? ? ? ? ? StringBuilder builder = new StringBuilder(64);

? ? ? ? ? ? builder.append(method.getDeclaringClass().getName());

? ? ? ? ? ? builder.append('#').append(method.getName());

? ? ? ? ? ? builder.append('(').append(eventType.getName());

? ? ? ? ? ? methodString = builder.toString();

? ? ? ? }

? ? }

? ? @Override

? ? public int hashCode() {

? ? ? ? return method.hashCode();

? ? }

? ? public Method getMethod() {

? ? ? ? return method;

? ? }

? ? public ThreadMode getThreadMode() {

? ? ? ? return threadMode;

? ? }

? ? public Class<?> getEventType() {

? ? ? ? return eventType;

? ? }

? ? public int getPriority() {

? ? ? ? return priority;

? ? }

? ? public boolean isSticky() {

? ? ? ? return sticky;

? ? }

? ? public String getMethodString() {

? ? ? ? return methodString;

? ? }

}

以上就是事件注冊(cè)\訂閱的完整流程

(三)、發(fā)布消息


SecondActivity.java中任意位置

EventBus.getDefault().post(new EventBean("EventBusMassage", 111111111));

EventBus.java

public void post(final Object obj) {

? ? // 從注冊(cè)事件中循環(huán)查詢(xún)

? ? Set<Object> objects = cacheMap.keySet();

? ? Iterator<Object> iterator = objects.iterator();

? ? while (iterator.hasNext()) {

? ? ? ? final Object next = iterator.next();

? ? ? ? List<SubscriberMethod> list = cacheMap.get(next);

? ? ? ? for (final SubscriberMethod subsMethod : list) {

? ? ? ? ? ? // 獲取到的類(lèi)的類(lèi)型是否和傳入或者發(fā)送消息的類(lèi)對(duì)象類(lèi)型相同

? ? ? ? ? ? if (subsMethod.getEventType().isAssignableFrom(obj.getClass())) {

? ? ? ? ? ? ? ? switch (subsMethod.getThreadMode()) {

? ? ? ? ? ? ? ? ? ? case MAIN:

? ? ? ? ? ? ? ? ? ? ? ? // 主線程---》主線程

? ? ? ? ? ? ? ? ? ? ? ? if (Looper.myLooper() == Looper.getMainLooper()) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? invoke(subsMethod, next, obj);

? ? ? ? ? ? ? ? ? ? ? ? } else { // 子線程---》主線程

? ? ? ? ? ? ? ? ? ? ? ? ? ? mHandler.post(new Runnable() {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @Override

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? public void run() {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? invoke(subsMethod, next, obj);

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? ? ? });

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? ? ? case BACKGROUND:

? ? ? ? ? ? ? ? ? ? ? ? // 主線程---》子線程

? ? ? ? ? ? ? ? ? ? ? ? if (Looper.myLooper() == Looper.getMainLooper()) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ExecutorService executorService = Executors.newFixedThreadPool(10);

? ? ? ? ? ? ? ? ? ? ? ? ? ? executorService.execute(new Runnable() {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @Override

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? public void run() {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? invoke(subsMethod, next, obj);

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? ? ? });

? ? ? ? ? ? ? ? ? ? ? ? } else { // 子線程---》子線程

? ? ? ? ? ? ? ? ? ? ? ? ? ? invoke(subsMethod, next, obj);

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

? ? }

}

// 方法調(diào)用并執(zhí)行

private void invoke(SubscriberMethod subsMethod, Object next, Object obj) {

? ? Method method = subsMethod.getMethod();

? ? try {

? ? ? ? method.invoke(next, obj);

? ? } catch (IllegalAccessException e) {

? ? ? ? e.printStackTrace();

? ? } catch (InvocationTargetException e) {

? ? ? ? e.printStackTrace();

? ? }

}

(四)、接受消息

MainActivity.java

@Subscribe(threadMode = ThreadMode.BACKGROUND)

public void handleMessages(EventBean eventBean) {

? ? Log.d("======>", eventBean.toString());

? ? Log.d("======", "handleMessages: MainActivity " + Thread.currentThread().getName());

}

(五)、注銷(xiāo)事件

MainActivity.java

@Override

protected void onDestroy() {

? ? super.onDestroy();

? ? EventBus.getDefault().unregister(this);

}

EventBus.java

// 注銷(xiāo)事件

public void unregister(Object subscriber) {

? ? List<SubscriberMethod> subscribedTypes = cacheMap.get(subscriber);

? ? if (subscribedTypes != null) {

? ? ? ? cacheMap.remove(subscriber);

? ? } else {

? ? ? ? Log.e("error", "Subscriber to unregister was not registered before: " + subscriber.getClass());

? ? }

}

參考文檔:http://www.itdecent.cn/p/d9516884dbd4

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 項(xiàng)目到了一定階段會(huì)出現(xiàn)一種甜蜜的負(fù)擔(dān):業(yè)務(wù)的不斷發(fā)展與人員的流動(dòng)性越來(lái)越大,代碼維護(hù)與測(cè)試回歸流程越來(lái)越繁瑣。這個(gè)...
    fdacc6a1e764閱讀 3,332評(píng)論 0 6
  • EventBus基本使用 EventBus基于觀察者模式的Android事件分發(fā)總線。 從這個(gè)圖可以看出,Even...
    顧氏名清明閱讀 693評(píng)論 0 1
  • 先吐槽一下博客園的MarkDown編輯器,推出的時(shí)候還很高興博客園支持MarkDown了,試用了下發(fā)現(xiàn)支持不完善就...
    Ten_Minutes閱讀 654評(píng)論 0 2
  • EventBus用法及解析 EventBus介紹: EventBus主要是用來(lái)組件之間進(jìn)行信息傳遞的,相對(duì)于接口回...
    111_222閱讀 631評(píng)論 0 1
  • EventBus 簡(jiǎn)介 EventBus 直譯過(guò)來(lái)就是事件總線,熟悉計(jì)算機(jī)原理的人一定很熟悉總線的概念,所有設(shè)備都...
    DanieX閱讀 1,095評(píng)論 0 1

友情鏈接更多精彩內(nèi)容