EventBus 3.0 正確使用、原理講解以及手寫實現

子曰:溫故而知新,可以爲師矣。 《論語》-- 孔子



一、常規的事件傳遞

  • Intent 意圖: 跳轉 + 傳參 (侷限性非常大)。
  • Handler:通常用來更新主線程 UI,使用不當容易出現內存泄漏。
  • Interface 接口:僅限於同一線程中數據交互。
  • BroadCastReceiver:有序廣播 + 無序廣播。 onReceive() 方法不能超過 10 秒。
  • AIDL 跨進程通信:代碼閱讀性不友好,維護成本偏高。
  • 其他方式:本地存儲…


二、EventBus 正確使用

1. 概念

  • 一個 Android 優化的 publish / subscribe 消息事件總線。簡化了應用程序內各個組件間,組件與後臺線程間的通信。

2. 使用場景。

  • 網絡請求,返回時通過 Handler 或者 BroadCastReceiver 通知更新主線程 UI;多個 Fragment 之間需要通過 Listener(監聽)通信。這些需求都可以通過 EventBus 完成和實現。

3. 官方架構圖

在這裏插入圖片描述

4. 正確使用

1)導包
// app 目錄下的 build.gradle 文件 defaultConfig 節點下加入 
//給註解處理器傳參
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [ eventBusIndex : 'com.kww.eventbusdemo.MyEventBusIndex' ]
            }
        }

 // dependencies 節點下
 implementation 'org.greenrobot:eventbus:3.2.0'
 annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.2.0'

2)註冊,反註冊,訂閱事件

public class BaseApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
    }
}
public class SendMessageEvent {
    private String message;

    public SendMessageEvent(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
// MainActivity
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity >>>>";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        EventBus.getDefault().register(this);

        findViewById(R.id.btn_jump).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this,SecondActivity.class));
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(EventBus.getDefault().isRegistered(this)){
            EventBus.getDefault().unregister(this);
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void receiveMessage(SendMessageEvent event){
        Log.e(TAG,event.getMessage());
    }
}

3)發送事件

public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        findViewById(R.id.btn_send_message).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().post(new SendMessageEvent("Hello"));
            }
        });
    }
}

4)運行程序,查看 Log 日誌:

com.kww.eventbusdemo E/MainActivity >>>>: Hello

5)EventBus 的四種 ThreadMode

  • POSTING(默認):如果使用事件處理函數指定了線程模型爲 POSTING,那麼該事件在哪個線程發佈出來的,事件處理函數就會在這個線程中運行,也就是說 發佈事件和接收事件在同一個線程。在線程模型爲 POSTING 的事件處理函數中儘量避免執行耗時操作,因爲它會阻塞事件的傳遞,甚至有可能會引起 ANR
  • MAIN:事件的處理會在 UI 線程中執行。事件處理時間不能太長,否則可能會導致ANR
  • BACKGROUND:如果事件是在 UI 線程中發佈出來的,那麼該事件處理函數就會在新的線程中運行,如果事件本來就是子線程中發佈出來的,那麼該事件處理函數直接在發佈事件的線程中執行。在此事件處理函數中禁止進行 UI 更新操作。
  • ASYNC:無論事件在哪個線程發佈,該事件處理函數都會在新建的 子線程 中執行,同樣,此事件處理函數中禁止進行 UI 更新操作。

6)粘性事件

// MainActivity 類
findViewById(R.id.btn_jump).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 發送粘性事件
                EventBus.getDefault().postSticky(new SendMessageEvent("粘性事件"));
                startActivity(new Intent(MainActivity.this,SecondActivity.class));
            }
        });

public class SecondActivity extends AppCompatActivity {

    private static final String TAG = "SecondActivity >>>>";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        EventBus.getDefault().register(this);


    @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
    public void receiveMessageStick(SendMessageEvent event){
        Log.e(TAG,event.getMessage());
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(EventBus.getDefault().isRegistered(this)){
            EventBus.getDefault().unregister(this);
        }
    }
}

這就類似於列表與詳情頁的關係,我們的 MainActivity 就是列表頁,我們發送了一個粘性事件,相當於我們點擊某一個 item,將當前 itemid 傳遞給 詳情頁去請求接口,那麼我們在 SecondActivity ,也就是 詳情頁,先收到粘性事件的 id,然後跳轉到詳情頁面上。


7)添加混淆

-keepattributes *Annotation*
-keepclassmembers class * {
    @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
 
# And if you use AsyncExecutor:
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
    <init>(java.lang.Throwable);
}

以上就是 EventBus 3.0 之後的正確使用,可能有的人和我用的不太一樣,其實上面這中寫法纔是正確的寫法,具體的可以看官方文檔:EventBus 註解處理器使用 以及GitHub傳送門



三、EventBus 3.0 之前源碼理解

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

在這行代碼中, EventBus.getDefault() 方法獲取的是 EventBus 對象,很明顯這是一個單例模式,採用了雙重檢查模式 (DCL):

 /** Convenience singleton for apps using a process-wide EventBus instance. */
    public static EventBus getDefault() {
        EventBus instance = defaultInstance;
        if (instance == null) {
            synchronized (EventBus.class) {
                instance = EventBus.defaultInstance;
                if (instance == null) {
                    instance = EventBus.defaultInstance = new EventBus();
                }
            }
        }
        return instance;
    }

我們看到 register() 方法的源碼:

 public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        // 用 subscriberMethodFinder 提供的方法,找到在 subscriber 這個類裏面訂閱的內容。
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

在這個方法中,它首先要拿到 List<SubscriberMethod> 這個集合,也就是傳進來的訂閱者所有的訂閱的方法,接下來遍歷訂閱者的訂閱方法來完成訂閱者的訂閱操作。對於SubscriberMethod(訂閱方法)類中,主要就是用保存訂閱方法的 Method 對象、線程模式、事件類型、優先級、是否是粘性事件等屬性。

public class SubscriberMethod {
    final Method method;
    final ThreadMode threadMode;
    final Class<?> eventType;
    final int priority;
    final boolean sticky;
    /** Used for efficient comparison */
    String methodString;
    //......
}

好的,我們進入這個 findSubscriberMethods() 方法,看一下是如何拿到訂閱者所有方法的:

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
       //從緩存中獲取SubscriberMethod集合
       List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
       if (subscriberMethods != null) {
           return subscriberMethods;
       }
       //ignoreGeneratedIndex屬性表示是否忽略註解器生成的MyEventBusIndex
       if (ignoreGeneratedIndex) {
        //通過反射獲取subscriberMethods
           subscriberMethods = findUsingReflection(subscriberClass);
       } else {
           subscriberMethods = findUsingInfo(subscriberClass);
       }
       //在獲得subscriberMethods以後,如果訂閱者中不存在@Subscribe註解並且爲public的訂閱方法,則會拋出異常。
       if (subscriberMethods.isEmpty()) {
           throw new EventBusException("Subscriber " + subscriberClass
                   + " and its super classes have no public methods with the @Subscribe annotation");
       } else {
           METHOD_CACHE.put(subscriberClass, subscriberMethods);
           return subscriberMethods;
       }
   }

首先從緩存中查找,如果找到了就立馬返回。如果緩存中沒有的話,則根據ignoreGeneratedIndex 選擇如何查找訂閱方法,該屬性默認就是false,它可以通過內部構建者類 EventBusBuilder 設置,表示是否忽略註解器生成的 MyEventBusIndex,這個就是採用我上面所寫的使用方式後,在編譯期 EventBus 就會自動幫我生成 MyEventBusIndex 文件。最後,找到訂閱方法後,放入緩存,以免下次繼續查找。

至於 findUsingReflection() 方法 和 findUsingReflection() 方法就不細說了,就是通過反射來獲取訂閱者中所有的方法。並依據方法的類型,參數和註解來找到根據 EventBus 指定的規則所寫的訂閱方法。

在查找完所有的訂閱方法以後便開始對所有的訂閱方法進行註冊:

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;
          //根據訂閱者和訂閱方法構造一個訂閱事件
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
          //獲取當前訂閱事件中Subscription的List集合
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
         //該事件對應的Subscription的List集合不存在,則重新創建並保存在subscriptionsByEventType中
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
        //訂閱者已經註冊則拋出EventBusException
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }
        //遍歷訂閱事件,找到比subscriptions中訂閱事件小的位置,然後插進去
        int size = subscriptions.size();
        for (int i = 0; i <= size; i++) {
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }
         //通過訂閱者獲取該訂閱者所訂閱事件的集合
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
          //將當前的訂閱事件添加到subscribedEvents中
        subscribedEvents.add(eventType);
        if (subscriberMethod.sticky) {
            if (eventInheritance) {
            //粘性事件的處理
                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);
            }
        }
    }

這段源碼做了兩件事,其一就是將 訂閱方法訂閱者 封裝到subscriptionsByEventTypetypesBySubscriber ,其二就是如果是粘性事件的話,就立馬投遞、執行。

  • subscriptionsByEventType:當我們 post 時,根據 EventType 找到訂閱事件,從而去分發事件,處理事件的。
  • typesBySubscriber:調用 unregister(this) 的時候,根據訂閱者找到 EventType,又根據 EventType 找到訂閱事件,從而對訂閱者進行解綁。

用一張圖來總結一下 register
在這裏插入圖片描述


2. EventBus.getDefault().post(new SendMessageEvent("Hello"));

現在來說一下 post發送。


    /** Posts the given event to the event bus. */
    public void post(Object event) {
        //PostingThreadState保存着事件隊列和線程狀態信息
        PostingThreadState postingState = currentPostingThreadState.get();
        //獲取事件隊列,並將當前事插入到事件隊列中
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (!postingState.isPosting) {
            postingState.isMainThread = isMainThread();
            postingState.isPosting = true;
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
                while (!eventQueue.isEmpty()) {
                    //處理隊列中的所有事件
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

首先從 PostingThreadState 對象中取出事件隊列,然後再將當前的事件插入到事件隊列當中。最後將隊列中的事件依次交由 postSingleEvent 方法進行處理,並移除該事件。來看看 postSingleEvent()方法裏做了什麼:

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
       Class<?> eventClass = event.getClass();
       boolean subscriptionFound = false;
       //eventInheritance表示是否向上查找事件的父類,默認爲true
       if (eventInheritance) {
          //通過lookupAllEventTypes找到所有的父類事件並存在List中,然後通過postSingleEventForEventType方法對事件逐一處理
           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) {
               post(new NoSubscriberEvent(this, event));
           }
       }
   }

接下來看看 postSingleEventForEventType方法:

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
      CopyOnWriteArrayList<Subscription> subscriptions;
         //取出該事件對應的Subscription集合
      synchronized (this) {
          subscriptions = subscriptionsByEventType.get(eventClass);
      }
      if (subscriptions != null && !subscriptions.isEmpty()) {
      //將該事件的event和對應的Subscription中的信息(包擴訂閱者類和訂閱方法)傳遞給postingState
          for (Subscription subscription : subscriptions) {
              postingState.event = event;
              postingState.subscription = subscription;
              boolean aborted = false;
              try {
                 //對事件進行處理
                  postToSubscription(subscription, event, postingState.isMainThread);
                  aborted = postingState.canceled;
              } finally {
                  postingState.event = null;
                  postingState.subscription = null;
                  postingState.canceled = false;
              }
              if (aborted) {
                  break;
              }
          }
          return true;
      }
      return false;
  }

接下來看看 postToSubscription()方法:

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    switch (subscription.subscriberMethod.threadMode) {
        case POSTING:
            invokeSubscriber(subscription, event);
            break;
        case MAIN:
            if (isMainThread) {
                invokeSubscriber(subscription, event);
            } else {
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case BACKGROUND:
            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);
    }
}

取出訂閱方法的線程模式,之後根據線程模式來分別處理。舉個例子,如果線程模式是 MAIN,提交事件的線程是主線程的話則通過反射,直接運行訂閱的方法,如果不是主線程,我們需要 mainThreadPoster 將我們的訂閱事件入隊列,mainThreadPosterHandlerPoster 類型的繼承自Handler,通過Handler 將訂閱方法切換到主線程執行。

下面用一張圖來說明一下 post 流程:
在這裏插入圖片描述

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

我們最後說一下解綁過程

public synchronized void unregister(Object subscriber) {
    List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
        for (Class<?> eventType : subscribedTypes) {
            unsubscribeByEventType(subscriber, eventType);
        }
        typesBySubscriber.remove(subscriber);
    } else {
        Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}

typesBySubscriber 就是在訂閱者註冊的過程中講到過這個屬性,它根據訂閱者找到 EventType,然後根據 EventType 和訂閱者來得到訂閱事件來對訂閱者進行解綁。



四、手寫 EventBus

// Subscribe 類
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Subscribe {

    ThreadMode threadMode() default ThreadMode.POSTING;
}
/**
 * 線程狀態
 */
public enum ThreadMode {

    // 事件的處理在和事件的發送在相同的進程,所以事件處理時間不應太長,不然影響事件的發送線程,而這個線程可能是UI線程
    POSTING,

    // 事件的處理會在UI線程中執行,事件處理不應太長時間
    MAIN,

    // 後臺進程,處理如保存到數據庫等操作
    BACKGROUND,

    // 異步執行,另起線程操作。事件處理會在單獨的線程中執行,主要用於在後臺線程中執行耗時操作
    ASYNC
}
/**
 * 保存符合要求的訂閱方法封裝類
 */
public class MethodManager {

    // 訂閱者的回調方法(註解方法)的參數類型
    private Class<?> type;

    // 訂閱者的回調方法(註解方法)的線程模式
    private ThreadMode threadMode;

    // 訂閱者的回調方法(註解方法)
    private Method method;

    public MethodManager(Class<?> type, ThreadMode threadMode, Method method) {
        this.type = type;
        this.threadMode = threadMode;
        this.method = method;
    }

    public Class<?> getType() {
        return type;
    }

    public void setType(Class<?> type) {
        this.type = type;
    }

    public ThreadMode getThreadMode() {
        return threadMode;
    }

    public void setThreadMode(ThreadMode threadMode) {
        this.threadMode = threadMode;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    @NonNull
    @Override
    public String toString() {
        return "MethodManager{" +
                "type=" + type +
                ", threadMode=" + threadMode +
                ", method=" + method +
                '}';
    }
}

public class EventBus {

    // volatile修飾的變量不允許線程內部緩存和重排序,即直接修改內存
    private static volatile EventBus instance;
    // 用來保存這些帶註解的方法(訂閱者的回調方法)
    private Map<Object, List<MethodManager>> cacheMap;

    private Handler handler;
    private ExecutorService executorService;

    private EventBus() {
        cacheMap = new HashMap<>();

        // Handler高級用法:將handler放在主線程使用
        handler = new Handler(Looper.getMainLooper());
        // 創建一個子線程(緩存線程池)
        executorService = Executors.newCachedThreadPool();
    }

    public static EventBus getDefault() {
        if (instance == null) {
            synchronized (EventBus.class) {
                if (instance == null) {
                    instance = new EventBus();
                }
            }
        }
        return instance;
    }

    // 找到MainActivity所有帶符合註解的方法
    public void register(Object getter) {
        // 獲取MainActivity所有的方法
        List<MethodManager> methodList = cacheMap.get(getter);
        if (methodList == null) { // 不爲空表示以前註冊完成
            methodList = findAnnotationMethod(getter);
            cacheMap.put(getter, methodList);
        }
    }

    // 獲取MainActivity中所有註解的方法
    private List<MethodManager> findAnnotationMethod(Object getter) {
        List<MethodManager> methodList = new ArrayList<>();
        // 獲取類
        Class<?> clazz = getter.getClass();
        // 獲取所有方法
        Method[] methods = clazz.getMethods();

        // 性能優化。N個父類不可能有自定義註解。排除後再反射
        while (clazz != null) {
            // 找出系統類,直接跳出,不添加cacheMap(因爲不是訂閱者)
            String clazzName = clazz.getName();
            if (clazzName.startsWith("java.") || clazzName.startsWith("javax.")
                    || clazzName.startsWith("android.")) {
                break;
            }

            // 循環方法
            for (Method method : methods) {
                // 獲取方法的註解
                Subscribe subscribe = method.getAnnotation(Subscribe.class);
                // 判斷註解不爲空,切記不能拋異常
                if (subscribe == null) {
                    continue;
                }
                // 嚴格控制方法格式和規範
                // 方法必須是返回void(一次匹配)
                Type returnType = method.getGenericReturnType();
                if (!"void".equals(returnType.toString())) {
                    throw new RuntimeException(method.getName() + "方法返回必須是void");
                }
                // 方法參數必須有值(二次匹配)
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length != 1) {
                    throw new RuntimeException(method.getName() + "方法有且只有一個參數");
                }

                // 完全符合要求、規範的方法,保存到方法對象中MethodManager(3個重要成員:方法、參數、線程)
                MethodManager manager = new MethodManager(parameterTypes[0], subscribe.threadMode(), method);
                methodList.add(manager);
            }

            // 不斷循環找出父類含有訂閱者(註解方法)的類。直到爲空,比如AppCompatActivity沒有吧
            clazz = clazz.getSuperclass();
        }
        return methodList;
    }

    // SecondActivity發送消息
    public void post(final Object setter) {
        // 訂閱者已經登記,從登記表中找出
        Set<Object> set = cacheMap.keySet();
        // 比如獲取MainActivity對象
        for (final Object getter : set) {
            // 獲取MainActivity中所有註解的方法
            List<MethodManager> methodList = cacheMap.get(getter);
            if (methodList != null) {
                // 循環每個方法
                for (final MethodManager method : methodList) {
                    // 有可能多個方法的參數一樣,從而都同時收到發送的消息
                    // 通過EventBean來判斷是否匹配上
                    if (method.getType().isAssignableFrom(setter.getClass())) {
                        // 通過方法的類型匹配,從SecondActivity發送的EventBean對象(參數)
                        // 匹配MainActivity中所有註解的方法符合要求的,都發送消息

                        // class1.isAssignableFrom(class2) 判定此 Class 對象所表示的類或接口
                        // 與指定的 Class 參數所表示的類或接口是否相同,或是否是其超類或超接口

                        // 線程調度
                        switch (method.getThreadMode()) {
                            case POSTING:
                                invoke(method, getter, setter);
                                break;

                            case MAIN:
                                // 先判斷髮送方是否在主線程
                                if (Looper.myLooper() == Looper.getMainLooper()) {
                                    invoke(method, getter, setter);
                                } else { // 子線程 - 主線程,切換線程(用到Handler)
                                    handler.post(new Runnable() {
                                        @Override
                                        public void run() {
                                            invoke(method, getter, setter);
                                        }
                                    });
                                }
                                break;

                            case BACKGROUND:
                                // 先判斷髮送方是否在主線程
                                if (Looper.myLooper() == Looper.getMainLooper()) {
                                    // 主線程 - 子線程,創建一個子線程(緩存線程池)
                                    executorService.execute(new Runnable() {
                                        @Override
                                        public void run() {
                                            invoke(method, getter, setter);
                                        }
                                    });
                                } else { // 子線程 到 子線程,不用切換線程
                                    invoke(method, getter, setter);
                                }
                                break;
                        }
                    }
                }
            }
        }
    }

    // 找到匹配方法後,通過反射調用MainActivity中所有符合要求的方法
    private void invoke(MethodManager method, Object getter, Object setter) {
        Method execute = method.getMethod();
        try {
            execute.invoke(getter, setter);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}





寫在文末

紙上得來終覺淺,絕知此事要躬行。 《冬夜讀書示子聿》-- 陸游

至此,EventBus正確使用原理理解以及 手寫實現 就說到這,各位看官食用愉快。


碼字不易,如果本篇文章對您哪怕有一點點幫助,請不要吝嗇您的點贊,我將持續帶來更多優質文章。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章