主流開源框架之EventBus深刻了解

主流開源框架源碼深刻了解第6篇——EventBus源碼分析。(源碼以3.1.1版爲準)java

EventBus簡介

EventBus是一個Android事件發佈/訂閱輕量級框架,經過此框架能夠解耦發佈者和訂閱者,能夠簡化Android的事件傳遞。事件傳遞既能夠用於Android的四大組件間的通信,也能夠用於異步線程和主線程通信。其最大的優勢在於,代碼簡潔、使用簡單以及將事件的發佈和訂閱充分的解耦。android

EventBus使用

public class EventActivity extends AppCompatActivity {

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

    @Override
    protected void onStart() {
        super.onStart();
        LogUtil.i("onStart1");
        // 官方demo 註冊事件在onStart中
        EventBus.getDefault().register(this);
    }

    /**
     * @Subscribe 訂閱者方法
     * 訂閱者方法將在發佈事件所在的線程中被調用。這是 默認的線程模式。事件的傳遞是同步的,
     * 一旦發佈事件,全部該模式的訂閱者方法都將被調用。這種線程模式意味着最少的性能開銷,
     * 由於它避免了線程的切換。所以,對於不要求是主線程而且耗時很短的簡單任務推薦使用該模式。
     * 使用該模式的訂閱者方法應該快速返回,以免阻塞發佈事件的線程,這多是主線程。
     * 注:POSTING 就是和發佈事件 post 所在一個線程中,post爲 主/子 線程POSTING就爲 主/子 線程中
     */
    @Subscribe(threadMode = ThreadMode.POSTING)
    public void onMessageEventPosting(EventBean member) {
        LogUtil.i(member.toString());
        LogUtil.i("onMessageEventPosting(), current thread is " + Thread.currentThread().getName());
    }

    /**
     * @Subscribe 訂閱者方法
     * 注:無論post發佈事件在什麼線程中,MAIN 都在主線程
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEventMain(EventBean member) {
        LogUtil.i(member.toString());
        TextView viewById = (TextView) findViewById(R.id.tv_event1);
        viewById.setText(member.toString());
        ToastUtil.showShortToast(member.toString());
        LogUtil.i("onMessageEventMain(), current thread is " + Thread.currentThread().getName());
    }

    /**
     * @Subscribe 訂閱者方法
     * 訂閱者方法將在主線程(UI線程)中被調用。所以,能夠在該模式的訂閱者方法中直接更新UI界面。
     * 事件將先進入隊列而後才發送給訂閱者,因此發佈事件的調用將當即返回。
     * 這使得事件的處理保持嚴格的串行順序。使用該模式的訂閱者方法必須快速返回,以免阻塞主線程。
     * 注:無論post發佈事件在什麼線程中,MAIN_ORDERED 也都在主線程,不過該模式事件是串行的,按前後順序的
     */
    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    public void onMessageEventMainOrdered(EventBean member) {
        LogUtil.i("onMessageEventMainOrdered(), current thread is " + Thread.currentThread().getName());
    }

    /**
     * @Subscribe 訂閱者方法
     * 注:post(發佈者)若爲子線程,則 BACKGROUND 則是於post同一子線程中,若post爲主線程,則BACKGROUND爲單獨的後臺線程
     */
    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onMessageEventBackground(EventBean member) {
        LogUtil.i("onMessageEventBackground(), current thread is " + Thread.currentThread().getName());
    }

    /**
     * @Subscribe 訂閱者方法
     * 注:post(發佈者)不管是在子線程仍是主線程,ASYNC 都會單開一個線程
     */
    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void onMessageEventAsync(EventBean member) {
        LogUtil.i("onMessageEventAsync(), current thread is " + Thread.currentThread().getName());
    }

    @Override
    protected void onStop() {
        super.onStop();
        LogUtil.i("onStop1");
        // 官方demo 解綁事件在onStop中
        EventBus.getDefault().unregister(this);
    }
}
複製代碼

EventBus分析流程

  1. EventBus初始化
  2. EventBus成員屬性
  3. EventBus線程切換
  4. Subscribe註解
  5. EventBus註冊
  6. 發佈事件EventBus(包括粘性事件)
  7. 取消註冊unregister
  8. Subscriber 索引

EventBus源碼分析

EventBus初始化

private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

// 方法一:EventBus.getDefault(),EventBus爲應用提供便利的單例
    public static EventBus getDefault() {
        // 雙重校驗並加鎖的單例模式
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }
// 方法二:new EventBus(); ,建立一個新的EventBus實例;每一個實例都是傳遞事件的單獨範圍。要使用中央總線,請考慮使用#getDefault()方式。
    public EventBus() {
        this(DEFAULT_BUILDER);
    }
複製代碼
  1. EventBus初始化有兩種方式,一種是EventBus本身爲開發者提供的便利用法,第二種則是直接實例化對象。
  2. 爲何EventBus的構造方法是public的呢? 這就要說到EventBus在咱們項目中,並非僅僅存在一條總線,也存在其它的總線。所以,咱們訂閱者也能夠訂閱到其它的總線之上,而後經過不一樣的EventBus發送數據。那麼,咱們須要注意的是,不一樣的EventBus發送的數據,是相互隔離開來的,訂閱者只會收到註冊到當前的EventBus發送的數據。
  3. 咱們最後看一下EventBus構造方法中傳入的DEFAULT_BUILDER,其實是EventBusBuilder。所以咱們就能夠了解到EventBus是經過建造者模式初始化的實例。

EventBus成員屬性

// EventBus類:
    private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();

    // 以Event事件爲key,以subscriptions訂閱者爲value,所以當發送Event時可經過該hashmap找到訂閱此事件的訂閱者
    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    // 以Subscriber訂閱者爲key,以types類型爲value,所以當發送註冊和反註冊時都會操做此hashmap
    private final Map<Object, List<Class<?>>> typesBySubscriber;
    // 維護粘性事件,使用併發的hashmap保存
    private final Map<Class<?>, Object> stickyEvents;

    // 線程內部數據存儲類,在指定的線程中存儲數據,也只能在指定線程中獲取到存儲數據。
    private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };

    // @Nullable
    private final MainThreadSupport mainThreadSupport;
    // @Nullable
    private final Poster mainThreadPoster;
    private final BackgroundPoster backgroundPoster;
    private final AsyncPoster asyncPoster;
    private final SubscriberMethodFinder subscriberMethodFinder;
    private final ExecutorService executorService;

    private final boolean throwSubscriberException;
    private final boolean logSubscriberExceptions;
    private final boolean logNoSubscriberMessages;
    private final boolean sendSubscriberExceptionEvent;
    private final boolean sendNoSubscriberEvent;
    private final boolean eventInheritance;

    private final int indexCount;
    private final Logger logger;

    EventBus(EventBusBuilder builder) {
        // 日誌打印
        logger = builder.getLogger();
        // 事件對應的 訂閱者和訂閱者方法集合映射的封裝類 存儲
        subscriptionsByEventType = new HashMap<>();
        // 註冊的訂閱者存儲
        typesBySubscriber = new HashMap<>();
        // 粘性事件存儲
        stickyEvents = new ConcurrentHashMap<>();
        mainThreadSupport = builder.getMainThreadSupport();
        // Android主線程處理事件
        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
        // Background事件發送者
        backgroundPoster = new BackgroundPoster(this);
        // 異步事件發送者
        asyncPoster = new AsyncPoster(this);
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        // @Subscribe註解方法找尋器
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        // 標識1:當調用事件處理函數時,若發生了異常是否進行異常信息打印。默認true
        logSubscriberExceptions = builder.logSubscriberExceptions;
        // 標識2:當沒有訂閱者訂閱該事件時,是否打印日誌。默認true
        logNoSubscriberMessages = builder.logNoSubscriberMessages;
        // 標識3:當調用事件處理函數時,若發生了異常是否發送SubscriberExceptionEvent這個事件。默認true
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        // 標識4:當沒有訂閱者訂閱該事件時,是否發送NoSubscriberEvent事件。默認true
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        // 標識5:是否拋出SubscriberException異常。默認false
        throwSubscriberException = builder.throwSubscriberException;
        // 標識6:與event有繼承關係的是否都須要發送。默認true
        eventInheritance = builder.eventInheritance;
        // 執行服務線程池
        executorService = builder.executorService;
    }
複製代碼

EventBus線程切換

EventBus的成員屬性中,咱們來簡單看一下其很是重要的三個Poster:mainThreadPoster、backgroundPoster、asyncPostersegmentfault

  1. mainThreadPoster:用於主線程切換。
    // EventBusBuilder類:
        MainThreadSupport getMainThreadSupport() {
            if (mainThreadSupport != null) {
                return mainThreadSupport;
            } else if (Logger.AndroidLogger.isAndroidLogAvailable()) {
                // 獲取主線程Looper,正常狀況不會爲null
                Object looperOrNull = getAndroidMainLooperOrNull();
                return looperOrNull == null ? null :
                        // 初始化MainThreadSupport,其實是AndroidHandlerMainThreadSupport對象
                        new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull);
            } else {
                return null;
            }
        }
    
        Object getAndroidMainLooperOrNull() {
            try {
                // 獲取主線程Looper
                return Looper.getMainLooper();
            } catch (RuntimeException e) {
                // 並非真正的功能性Android(例如,「 Stub!」 Maven依賴項)
                return null;
            }
        }
    
        public interface MainThreadSupport {
    
            boolean isMainThread();
    
            Poster createPoster(EventBus eventBus);
    
            class AndroidHandlerMainThreadSupport implements MainThreadSupport {
    
                private final Looper looper;
    
                public AndroidHandlerMainThreadSupport(Looper looper) {
                    // 初始化looper屬性,此處就是上面傳進來的主線程Looper
                    this.looper = looper;
                }
    
                @Override
                public boolean isMainThread() {
                    // 判斷是否爲主線程
                    return looper == Looper.myLooper();
                }
    
                @Override
                public Poster createPoster(EventBus eventBus) {
                    // 初始化HandlerPoster,實際是Handler子類
                    return new HandlerPoster(eventBus, looper, 10);
                }
            }
    
        }
    複製代碼
    從構造函數中mainThreadPoster初始化,其實是經過mainThreadSupport.createPoster(this),而mainThreadSupport經過分析,咱們能夠了解其實是AndroidHandlerMainThreadSupport類的對象。所以經過調用其createPoster(this)方法最後返回了HandlerPoster。
    // 繼承自Handler
    public class HandlerPoster extends Handler implements Poster {
    
        // PendingPostQueue隊列,用於保存用於即將執行的,待發送的post隊列
        private final PendingPostQueue queue;
        // 表示post事件能夠最大的在HandlerMessage中存活時間。規定最大的運行時間,由於運行在主線程,不能阻塞主線程。
        private final int maxMillisInsideHandleMessage;
        private final EventBus eventBus;
        // 標識Handler是否有效,便是否運行起來啦
        private boolean handlerActive;
    
        protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
            // 此處傳入經過調用createPoster(this)方法,
            // 傳入保存到AndroidHandlerMainThreadSupport成員屬性的主線程looper。
            // 所以HandlerPoster是主線程的Handler,用於將EventBus異步線程消息切換回主線程。
            super(looper);
            // 將createPoster(this),傳入的this,即EventBus保存
            this.eventBus = eventBus;
            this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
            queue = new PendingPostQueue();
        }
    
        // 消息入隊,若此Handler已運行,則直接發送obtainMessage消息,最終回到下面的handleMessage中處理入隊消息。
        public void enqueue(Subscription subscription, Object event) {
            // 根據傳進來的參數封裝PendingPost待處理post對象。PendingPost的封裝,使用了數據緩存池。
            PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
            synchronized (this) {
                // 待處理消息入隊
                queue.enqueue(pendingPost);
                if (!handlerActive) {
                    handlerActive = true;
                    // 調用sendMessage,發送事件回到主線程,最終會調用下面的handleMessage方法
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                }
            }
        }
    
        // Handler中最重要的方法就是handleMessage,全部的消息處理最後都會通過此方法。
        @Override
        public void handleMessage(Message msg) {
            boolean rescheduled = false;
            try {
                long started = SystemClock.uptimeMillis();
                // 無限循環
                while (true) {
                    // 從隊列中取出消息
                    PendingPost pendingPost = queue.poll();
                    // 雙重判斷並加鎖,若pendingPost爲null,則返回
                    if (pendingPost == null) {
                        synchronized (this) {
                            // Check again, this time in synchronized
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                handlerActive = false;
                                return;
                            }
                        }
                    }
                    // 使用反射的方法調用訂閱者的訂閱方法,進行事件的分發。
                    eventBus.invokeSubscriber(pendingPost);
                    long timeInMethod = SystemClock.uptimeMillis() - started;
                    // 每次分發完事件都會從新比較一下處於此循環的時間,若大於最大設定值則返回
                    if (timeInMethod >= maxMillisInsideHandleMessage) {
                        if (!sendMessage(obtainMessage())) {
                            throw new EventBusException("Could not send handler message");
                        }
                        rescheduled = true;
                        return;
                    }
                }
            } finally {
                handlerActive = rescheduled;
            }
        }
    }
    複製代碼
  2. backgroundPoster:後臺消息切換。
    // 實現Runnable接口
    final class BackgroundPoster implements Runnable, Poster {
    
        private final PendingPostQueue queue;
        private final EventBus eventBus;
        // 標識此Runnable是否正在運行
        private volatile boolean executorRunning;
    
        BackgroundPoster(EventBus eventBus) {
            // 初始化eventBus屬性
            this.eventBus = eventBus;
            // 初始化待處理post隊列
            queue = new PendingPostQueue();
        }
    
        // 消息入隊,若此Runnable正在運行,則經過eventBus獲取其初始化時構造的線程池,執行當前任務,最終回到下面的run方法中。
        public void enqueue(Subscription subscription, Object event) {
            // 根據傳進來的參數封裝PendingPost待處理post對象。PendingPost的封裝,使用了數據緩存池。
            PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
            synchronized (this) {
                // 消息入隊
                queue.enqueue(pendingPost);
                if (!executorRunning) {
                    executorRunning = true;
                    // 經過eventBus成員獲取在EventBus構造方法中初始化的線程池,而後執行當前Runnable
                    eventBus.getExecutorService().execute(this);
                }
            }
        }
    
        @Override
        public void run() {
            try {
                try {
                    while (true) {
                        // 雙重判斷並加鎖,若pendingPost爲null,則返回
                        PendingPost pendingPost = queue.poll(1000);
                        if (pendingPost == null) {
                            synchronized (this) {
                                // Check again, this time in synchronized
                                pendingPost = queue.poll();
                                if (pendingPost == null) {
                                    executorRunning = false;
                                    return;
                                }
                            }
                        }
                        // 經過eventBus執行分發事件,此while循環會將隊列中全部消息都取出,並分發。
                        eventBus.invokeSubscriber(pendingPost);
                    }
                } catch (InterruptedException e) {
                    eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
                }
            } finally {
                executorRunning = false;
            }
        }
    }
    複製代碼
  3. asyncPoster:
    // 實現Runnable接口
    class AsyncPoster implements Runnable, Poster {
    
        private final PendingPostQueue queue;
        private final EventBus eventBus;
    
        AsyncPoster(EventBus eventBus) {
            this.eventBus = eventBus;
            queue = new PendingPostQueue();
        }
    
        // 消息入隊,直接使用evnetBus中線程池執行當前Runnable,最終回到run方法中
        public void enqueue(Subscription subscription, Object event) {
            PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
            queue.enqueue(pendingPost);
            eventBus.getExecutorService().execute(this);
        }
    
        @Override
        public void run() {
            // 獲取消息隊列中的消息
            PendingPost pendingPost = queue.poll();
            if(pendingPost == null) {
                throw new IllegalStateException("No pending post available");
            }
            // 只執行消息隊列中的一個消息即結束
            eventBus.invokeSubscriber(pendingPost);
        }
    }
    複製代碼

小結

  1. 三個Poster均實現了Poster接口,此接口只有enqueue一個方法。此方法用於消息入隊,而後經過Handler發送obtainMessage消息或者線程池執行當前Runnable任務,最終回到消息隊列處理的方法中,即handleMessage或者run方法。
  2. backgroundPoster和asyncPoster實際上很類似,差異在於backgroundPoster會一次性將消息隊列中的消息經過eventBus分發完,而asyncPoster一次只分發一個。
  3. 三個Poster入隊的消息最後都被封裝爲PendingPost對象,此類的封裝,使用了數據緩存池。PendingPost類內部維護一個類型PendingPost的ArrayList,最大容量爲10000。每個PendingPost消息被分發完成,都會調用PendingPost#releasePendingPost方法釋放其內部成員屬性值,並將其添加到內部集合中,已備調用obtainPendingPost而複用,這樣就減小了初始化PendingPost對象的時間,直接更改其內部屬性值以提升效率。
    final class PendingPost {
        private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>();
    
        Object event;
        Subscription subscription;
        PendingPost next;
    
        private PendingPost(Object event, Subscription subscription) {
            this.event = event;
            this.subscription = subscription;
        }
        // 複用或者建立新的obtainPendingPost
        static PendingPost obtainPendingPost(Subscription subscription, Object event) {
            synchronized (pendingPostPool) {
                int size = pendingPostPool.size();
                if (size > 0) {
                    // 移除並獲取最後一位PendingPost
                    PendingPost pendingPost = pendingPostPool.remove(size - 1);
                    // 重置成員屬性值
                    pendingPost.event = event;
                    pendingPost.subscription = subscription;
                    pendingPost.next = null;
                    return pendingPost;
                }
            }
            return new PendingPost(event, subscription);
        }
        // 釋放PendingPost成員屬性保存的值
        static void releasePendingPost(PendingPost pendingPost) {
            // 清空屬性值
            pendingPost.event = null;
            pendingPost.subscription = null;
            pendingPost.next = null;
            synchronized (pendingPostPool) {
                // Don't let the pool grow indefinitely if (pendingPostPool.size() < 10000) { pendingPostPool.add(pendingPost); } } } } 複製代碼

Subscribe註解

// 註解的使用:@Subscribe(threadMode = ThreadMode.MAIN, sticky = false, priority = 2)

/**
 * Java四大元註解:
 * 1. @Target :用於描述註解的使用範圍,也就是說使用了@Target去定義一個註解,那麼能夠決定定義好的註解能用在什麼地方
 *    內部值:ElementType[]  value()數組, value值類型   ElementType枚舉類型
 *    元註解中的枚舉值決定了,一個註解能夠標記的範圍
 *      TYPE : 只能用在類、接口、枚舉類型上。
 *      FIELD :字段聲明和枚舉常量
 *      METHOD :只能用在方法聲明上
 *      PARAMETER : 只能用在參數的聲明上 【參數名】
 *      CONSTRUCTOR : 只能用在構造方法的聲明上
 *      LOCAL_VARIABLE : 只能用在局部變量聲明上
 *      ANNOTATION_TYPE :只能用在註解上
 *      PACKAGE :只能用在包上
 *      TYPE_PARAMETER : 參數類型【形式參數類型】
 *      TYPE_USE : 任何位置均可以
 * 2. @Retention:用於描述一個註解存在的生命週期【源碼,字節碼文件,運行時】
 * 	    內部值:RetentionPolicy value();非數組,意味着只能一個值
 * 	    值類型:枚舉值RetentionPolicy,幾個值決定了幾個狀態。以下幾個值:
 * 		SOURCE :表示一個註解能夠存在於源碼中==>java的源碼中
 *      CLASS :表示 一個註解能夠在源碼中,而且能夠在字節碼文件中
 *      RUNTIME :表示 一個註解能夠在源碼、字節碼、及運行時期該註解都會存在
 * 3. @Document :使用了該註解後,將自定義註解設置爲文檔說明內容,在生成javadoc時會將該註解加入到文檔中。
 * 4. @Inherited :用於標註一個父類的註解是否能夠被子類繼承,若是一個註解須要被其子類所繼承,則在聲明時直接使用@Inherited註解便可。若是沒有寫此註解,則沒法被子類繼承。
 * 	    不是說註解與註解之間可否相互繼承,而是說:一個類A被註解了,那麼另一個類B,繼承了A類,B類可以繼承到A類中,的註解 (即被@Inherited註解過的註解)
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    // 線程模式:對應mainThreadPoster、backgroundPoster、asyncPoster這三個Poster
    ThreadMode threadMode() default ThreadMode.POSTING; // 默認的POSTING,不管消息處於什麼線程,都直接分發,不作線程切換

    // 是不是粘性事件
    boolean sticky() default false;

    // 訂戶優先級影響事件傳遞的順序。在同一傳送線程ThreadMode中,優先級較高的訂戶將在優先級較低的其餘訂戶以前接收事件。默認優先級爲0。
    // 注意:優先級不會影響具備不一樣ThreadMode的訂戶之間發送的順序!
    int priority() default 0;
}
複製代碼

註冊EventBus—register(this)

// EventBus類:
    public void register(Object subscriber) {
        // 獲取訂閱者的Class對象
        Class<?> subscriberClass = subscriber.getClass();
        // 經過訂戶方法查找器(經過註解查找)找到訂閱者裏訂閱方法的集合
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            // 遍歷集合按個執行訂閱
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }
複製代碼

註冊方法中總共完成兩件事情:1. 查找訂閱方法集合 2. 遍歷集合按個訂閱數組

  • 查找訂閱方法集合
    // 訂閱方法對象
    public class SubscriberMethod {
        final Method method;    // 訂閱的方法
        final ThreadMode threadMode;    // 線程模式
        final Class<?> eventType;   // 事件類型:即咱們訂閱方法的惟一參數,就是事件類型;同時也是post(T)的參數。
        final int priority; // 優先級
        final boolean sticky;   // 是否爲粘性事件
        String methodString;    // 用於有效比較,是否同一個訂閱方法
    }
    
    // 訂閱方法查找器
    class SubscriberMethodFinder {
        // 用於緩存訂閱者和訂閱者訂閱方法集合
        private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
        private static final int POOL_SIZE = 4;
        // FindState數組,緩存大小爲4
        private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
    
        // 查找訂閱方法集合
        List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
            List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
            // 先查找緩存
            if (subscriberMethods != null) {
                return subscriberMethods;
            }
            // 默認爲0
            if (ignoreGeneratedIndex) {
                // 使用反射查找,耗費性能
                subscriberMethods = findUsingReflection(subscriberClass);
            } else {
                // 查找使用信息
                subscriberMethods = findUsingInfo(subscriberClass);
            }
            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;
            }
        }
    
        // FindState中間器,用於查找保存狀態
        static class FindState {
            // 保存訂閱方法
            final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
            // 以事件類型爲key,方法爲value
            final Map<Class, Object> anyMethodByEventType = new HashMap<>();
            // 以方法爲key,訂閱者的Class對象爲value
            final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
            final StringBuilder methodKeyBuilder = new StringBuilder(128);
    
            Class<?> subscriberClass;
            Class<?> clazz;
            boolean skipSuperClasses;
            SubscriberInfo subscriberInfo;
            // 初始化傳入訂閱類
            void initForSubscriber(Class<?> subscriberClass) {
                this.subscriberClass = clazz = subscriberClass;
                skipSuperClasses = false;
                subscriberInfo = null;
            }
    
            // 回收釋放,已備複用
            void recycle() {
                ...
            }
    
            // 用來判斷FindState的anyMethodByEventType map是否已經添加過以當前eventType爲key的鍵值對,沒添加過則返回true
            boolean checkAdd(Method method, Class<?> eventType) {
                ...
            }
    
            // 移動到父類Class
            void moveToSuperclass() {
                ...
            }
        }
    
        private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
            // 準備FindState對象
            FindState findState = prepareFindState();
            // findState中間器初始化訂閱者
            findState.initForSubscriber(subscriberClass);
            while (findState.clazz != null) {
                // 獲取subscriberInfo,默認爲null。此方法會在【Subscriber 索引】詳細講解。
                findState.subscriberInfo = getSubscriberInfo(findState);
                if (findState.subscriberInfo != null) {
                    SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
                    for (SubscriberMethod subscriberMethod : array) {
                        if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                            findState.subscriberMethods.add(subscriberMethod);
                        }
                    }
                } else {
                    // 經過反射查找
                    findUsingReflectionInSingleClass(findState);
                }
                // 轉移到父類Class
                findState.moveToSuperclass();
            }
            // 經過findState獲取方法並緩存findState
            return getMethodsAndRelease(findState);
        }
    
        // FindState的緩存大小爲4,並使用一維的靜態數組,因此這裏須要注意線程同步的問題
        private FindState prepareFindState() {
            // 如有緩存則直接返回,不然建立
            synchronized (FIND_STATE_POOL) {
                for (int i = 0; i < POOL_SIZE; i++) {
                    FindState state = FIND_STATE_POOL[i];
                    if (state != null) {
                        FIND_STATE_POOL[i] = null;
                        return state;
                    }
                }
            }
            return new FindState();
        }
    
        // 在單個類中使用反射查找訂閱方法
        private void findUsingReflectionInSingleClass(FindState findState) {
            Method[] methods;
            try {
                // 獲取全部聲明的方法
                methods = findState.clazz.getDeclaredMethods();
            } catch (Throwable th) {
                // 獲取訂閱者中聲明的public方法,跳過父類
                methods = findState.clazz.getMethods();
                findState.skipSuperClasses = true;
            }
            for (Method method : methods) {
                // 得到方法的修飾符
                int modifiers = method.getModifiers();
                // 若是是public類型,但非abstract、static等
                if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                    // 得到當前方法全部參數的類型
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    // 若是當前方法只有一個參數
                    if (parameterTypes.length == 1) {
                        Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                        // 若是當前方法使用了Subscribe註解
                        if (subscribeAnnotation != null) {
                            // 獲得該方法參數的類型
                            Class<?> eventType = parameterTypes[0];
                            // checkAdd()方法用來判斷FindState的anyMethodByEventType map是否已經添加過以當前eventType爲key的鍵值對,沒添加過則返回true
                            if (findState.checkAdd(method, eventType)) {
                                // 獲得Subscribe註解的threadMode屬性值,即線程模式
                                ThreadMode threadMode = subscribeAnnotation.threadMode();
                                // 建立一個SubscriberMethod對象,並添加到subscriberMethods集合
                                findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                        subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                            }
                        }
                    } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                        String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                        throw new EventBusException("@Subscribe method " + methodName +
                                "must have exactly 1 parameter but has " + parameterTypes.length);
                    }
                } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                    String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                    throw new EventBusException(methodName +
                            " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
                }
            }
        }
    
        // 從findState中間件中獲取訂閱的方法集合,並釋放findState中間件,最後將findState緩存到數組中
        private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
            List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
            findState.recycle();
            synchronized (FIND_STATE_POOL) {
                for (int i = 0; i < POOL_SIZE; i++) {
                    if (FIND_STATE_POOL[i] == null) {
                        FIND_STATE_POOL[i] = findState;
                        break;
                    }
                }
            }
            return subscriberMethods;
        }
    }
    複製代碼
  • 遍歷集合按個訂閱
    // EventBus類:
        // 必須在同步塊中調用
        private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
             // 獲得當前訂閱了事件的方法的參數類型
            Class<?> eventType = subscriberMethod.eventType;
            // Subscription類保存了要註冊的類對象以及當前的subscriberMethod
            Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
            // subscriptionsByEventType是一個HashMap,保存了以eventType爲key,Subscription對象集合爲value的鍵值對
            // 先查找subscriptionsByEventType是否存在以當前eventType爲key的值
            CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
            // 若是不存在,則建立一個subscriptions,並保存到subscriptionsByEventType
            if (subscriptions == null) {
                subscriptions = new CopyOnWriteArrayList<>();
                // '綁定訂閱者、訂閱方法和事件類型的集合,subscriptions真正的值,在下面for循環中根據訂閱方法優先級添加'
                subscriptionsByEventType.put(eventType, subscriptions);
            } else {
                if (subscriptions.contains(newSubscription)) {
                    throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                            + eventType);
                }
            }
            // 添加上邊建立的newSubscription對象到subscriptions中
            int size = subscriptions.size();
            for (int i = 0; i <= size; i++) {
                // 按照優先級將訂閱方法添加置subscriptions中,其實是保存到subscriptionsByEventType集合中
                if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                    subscriptions.add(i, newSubscription);
                    break;
                }
            }
            // typesBySubscribere也是一個HashMap,保存了以當前要註冊類的對象爲key,註冊類中訂閱事件的方法的參數類型的集合爲value的鍵值對
            // 查找是否存在對應的參數類型集合
            List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
            // 不存在則建立一個subscribedEvents,並保存到typesBySubscriber
            if (subscribedEvents == null) {
                subscribedEvents = new ArrayList<>();
                typesBySubscriber.put(subscriber, subscribedEvents);
            }
            // 保存當前訂閱了事件的方法的參數類型
            subscribedEvents.add(eventType);
            // 粘性事件相關的
            if (subscriberMethod.sticky) {
                // 判斷事件的繼承性,默認是true
                if (eventInheritance) {
                    // 獲取全部粘性事件並遍歷,stickyEvents就是發送粘性事件時,保存了事件類型和對應事件
                    Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
                    for (Map.Entry<Class<?>, Object> entry : entries) {
                        Class<?> candidateEventType = entry.getKey();
                        // isAssignableFrom:斷定此 Class 對象所表示的類或接口與指定的 Class 參數所表示的類或接口是否相同,或是不是其超類或超接口。若是是則返回 true;不然返回 falseif (eventType.isAssignableFrom(candidateEventType)) {
                            // 獲取粘性事件
                            Object stickyEvent = entry.getValue();
                            // 處理粘性事件
                            checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                        }
                    }
                } else {
                    // 獲取並處理粘性事件
                    Object stickyEvent = stickyEvents.get(eventType);
                    checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                }
            }
        }
    
        // 處理粘性事件
        private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
            if (stickyEvent != null) {
                // 發佈到訂閱者相應方法中
                postToSubscription(newSubscription, stickyEvent, isMainThread());
            }
        }
    
        // 粘性事件訂閱者,在註冊時,會及時收到事件,就是在註冊後經過此方法將粘性事件及時發佈的
        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 {
                        // 若是是在子線程發送事件,則將事件入隊列,經過Handler切換到主線程執行處理事件
                        mainThreadPoster.enqueue(subscription, event);
                    }
                    break;
                case MAIN_ORDERED:
                    // 不管在那個線程發送事件,都先將事件入隊列,而後經過 Handler 切換到主線程,依次處理事件。mainThreadPoster不會爲null
                    if (mainThreadPoster != null) {
                        mainThreadPoster.enqueue(subscription, event);
                    } else {
                        // temporary: technically not correct as poster not decoupled from subscriber
                        invokeSubscriber(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);
            }
        }
    
        // 用反射來執行訂閱事件的方法,這樣發送出去的事件就被訂閱者接收並作相應處理
        void invokeSubscriber(Subscription subscription, Object event) {
            try {
                subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
            } catch (InvocationTargetException e) {
                handleSubscriberException(subscription, event, e.getCause());
            } catch (IllegalAccessException e) {
                throw new IllegalStateException("Unexpected exception", e);
            }
        }
    複製代碼
  • 總結:
    1. 初始化EventBus對象時傳入一個EventBus.Builder對象對EventBus進行初始化,其中有三個比較重要的集合和一個SubscriberMethodFinder對象。
    2. 調用register方法,首先獲取訂閱者的Class對象,而後經過SubscriberMethodFinder對象獲取訂閱者中全部訂閱方法集合,它先從緩存中獲取,若是緩存中有,直接返回;若是緩存中沒有,經過反射的方式去遍歷訂閱者類內部被Subscribe註解的方法,將這些參數只有一個的方法放入到集合中進行返回。
    3. 按個將全部訂閱者和對應事件方法進行綁定。在綁定以後會判斷綁定的事件是不是粘性事件,若是是粘性事件,直接調用postToSubscription方法,將以前發送的粘性事件發送給訂閱者。這就是粘性事件爲何在事件發送去以後,再註冊該事件時,還能接受到此消息的。

發佈事件EventBus—post(event)

// EventBus類:
    // 發佈的線程狀態
    final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<>();  // 事件隊列
        boolean isPosting;  // 是否正在發佈
        boolean isMainThread;   // 是否在主線程
        Subscription subscription;  // 訂閱者和訂閱方法封裝類
        Object event;   // 事件
        boolean canceled;   // 取消標誌位
    }

    // ThreadLocal使用方法很簡單:get()和set(T)
    // ThreadLocal內部維護一個靜態內部類ThreadLocalMap。每一個Thread中都具有一個ThreadLocalMap,而ThreadLocalMap能夠存儲以ThreadLocal爲key的鍵值對。
    private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        // initialValue方法,同一個線程使用ThreadLocal#get()方法時,只有第一次會調用,即同一個線程使用的PostingThreadState對象是同一個。
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };

    // 1. 將給定事件發佈到事件總線
    public void post(Object event) {
        // currentPostingThreadState其實是:ThreadLocal<PostingThreadState>
        // Threadlocal而是一個線程內部的存儲類,能夠在指定線程內存儲數據,數據存儲之後,只有指定線程能夠獲得存儲數據
        // 所以,如果同一個線程,則postingState是惟一的,能夠類比成單例。
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        // 將事件添加到事件隊列中,即同一線程post發佈的全部事件都在該隊列中
        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;
            }
        }
    }

    // 1.1 發佈單個事件
    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        // 判斷事件的繼承性,默認是true
        if (eventInheritance) {
            // 查找全部事件類型,包括父類和接口
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            // 遍歷Class集合,繼續處理事件
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                // 經過postSingleEventForEventType方法返回的boolean值和subscriptionFound,進行或運算,subscriptionFound默認爲false
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        // 若subscriptionFound爲false,則證實沒有訂閱者訂閱此事件
        if (!subscriptionFound) {
            if (logNoSubscriberMessages) {
                logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                // 發送 '沒有訂閱者事件' 事件
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

    // 1.1.1 查找全部Class對象,包括超類和接口。
    private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
        synchronized (eventTypesCache) {
            // 先查找緩存
            List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
            // 緩存沒有則遍歷查找
            if (eventTypes == null) {
                eventTypes = new ArrayList<>();
                Class<?> clazz = eventClass;
                while (clazz != null) {
                    eventTypes.add(clazz);  // 添加當前事件類型
                    // 獲取當前事件類實現的全部接口,添加到事件類型集合中
                    addInterfaces(eventTypes, clazz.getInterfaces());
                    clazz = clazz.getSuperclass();
                }
                // 經過以事件Class類型位key,緩存跟此事件有關的全部事件
                eventTypesCache.put(eventClass, eventTypes);
            }
            return eventTypes;
        }
    }

    // 1.1.1.1 經過父接口遞歸,添加事件的父接口類型
    static void addInterfaces(List<Class<?>> eventTypes, Class<?>[] interfaces) {
        // 遍歷當前事件類所實現的全部接口
        for (Class<?> interfaceClass : interfaces) {
            // 若事件集合不包含此接口,則添加,並獲取接口的父接口,繼續迭代
            if (!eventTypes.contains(interfaceClass)) {
                eventTypes.add(interfaceClass);
                // 繼續迭代
                addInterfaces(eventTypes, interfaceClass.getInterfaces());
            }
        }
    }

    // 1.1.2 針對事件類型發佈單個事件
    private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            // 經過事件類型,獲取 訂閱者和訂閱者方法集合映射的封裝類 集合
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            // 遍歷subscriptions集合
            for (Subscription subscription : subscriptions) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;
                try {
                    // 發佈到訂閱
                    postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {
                    // 重置postingState
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }

    // 1.1.2.1 最後發佈到訂閱者,根據線程模式,進行線程切換
    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 {
                     // 若是是在子線程發送事件,則將事件入隊列,經過Handler切換到主線程執行處理事件
                     mainThreadPoster.enqueue(subscription, event);
                 }
                 break;
             case MAIN_ORDERED:
                 // 不管在那個線程發送事件,都先將事件入隊列,而後經過 Handler 切換到主線程,依次處理事件。mainThreadPoster不會爲null
                 if (mainThreadPoster != null) {
                     mainThreadPoster.enqueue(subscription, event);
                 } else {
                     // temporary: technically not correct as poster not decoupled from subscriber
                     invokeSubscriber(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);
         }
    }

     // 1.1.2.1.1 用反射來執行訂閱事件的方法,這樣發送出去的事件就被訂閱者接收並作相應處理
    void invokeSubscriber(Subscription subscription, Object event) {
        try {
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
            handleSubscriberException(subscription, event, e.getCause());
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception", e);
        }
    }
複製代碼

總結:緩存

  1. 獲取當前線程的事件隊列,將要發佈的事件加入到隊列中。而後遍歷整個隊列,邊移除遍歷的當前事件,邊發佈當前事件。
  2. 獲取事件的Class對象,找到當前的event的全部父類和實現的接口的class集合。遍歷這個集合,發佈集合中的每個事件。
  3. 經過事件類型,獲取 訂閱者和訂閱者方法集合映射的封裝類 集合,遍歷集合,將事件發送給訂閱者。
  4. 發送給訂閱者時,根據訂閱者的訂閱方法註解中的線程模式,判斷是否須要線程切換,若須要則切換線程進行調用,不然直接執行發佈。
  5. 用反射來執行訂閱事件的方法,這樣發送出去的事件就被訂閱者接收並作相應處理。

如果粘性事件,則先添加到粘性事件集合中,再發布事件:bash

// EventBus類:
    public void postSticky(Object event) {
        synchronized (stickyEvents) {
            // 添加到粘性事件集合,以備事件發佈以後,訂閱該事件的訂閱者註冊該事件時,依舊可以及時收到該事件
            // 具體可回顧【註冊EventBus—register(this)--遍歷集合按個訂閱】部分,查看如何註冊後便可及時收到粘性事件
            stickyEvents.put(event.getClass(), event);
        }
        // 調用普通事件的發佈方法,及時發佈
        post(event);
    }
複製代碼

EventBus-unregister(subscriber)

// EventBus類:
    // 從全部事件類中註銷給定的訂閱者
    public synchronized void unregister(Object subscriber) {
        // 獲取訂閱者訂閱的全部事件
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            // 遍歷訂閱類型集合,釋放以前緩存的當前類中的Subscription
            for (Class<?> eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);
            }
            // 刪除以subscriber爲key的鍵值對,更新typesBySubscriber
            typesBySubscriber.remove(subscriber);
        } else {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

    // 僅更新subscriptionsByEventType,而不更新typesBySubscriber
    private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        // 獲得當前參數類型對應的Subscription集合
        List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {
            int size = subscriptions.size();
            // 遍歷Subscription集合
            for (int i = 0; i < size; i++) {
                Subscription subscription = subscriptions.get(i);
                 // 若是當前subscription對象對應的註冊類對象 和 要取消註冊的註冊類對象相同,則刪除當前subscription對象
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }
複製代碼

總結:unregister中釋放了typesBySubscriber、subscriptionsByEventType中緩存的資源。併發

Subscriber 索引

EventBus主要是在項目運行時經過反射來查找訂事件的方法信息,若是項目中有大量的訂閱事件的方法,必然會對項目運行時的性能產生影響。其實除了在項目運行時經過反射查找訂閱事件的方法信息,EventBus在3.0以後增長了註解處理器,在程序的編譯時候,就能夠根據註解生成相對應的代碼,相對於以前的直接經過運行時反射,大大提升了程序的運行效率,可是在3.0默認的是經過反射去查找用@Subscribe標註的方法,來生成一個輔助的索引類來保存這些信息,這個索引類就是Subscriber Index,和 ButterKnife 的原理是相似的。框架

SubscriberInfoIndex使用(以【EventBus使用爲例】)

  1. App build.gradle依賴:
dependencies {
    implementation 'org.greenrobot:eventbus:3.1.1'
    // 引入註解處理器
    annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'
}
複製代碼
  1. App build.gradle配置註解生成類選項:
android {
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                // 根據項目實際狀況,指定輔助索引類的名稱和包名
                arguments = [ eventBusIndex : 'com.android.framework.CustomEventBusIndex' ]
            }
        }
    }
    ...
複製代碼
  1. Application中配置:
// CustomEventBusIndex此類由EventBus註解處理器,在項目編譯階段動態生成
EventBus.builder().addIndex(new CustomEventBusIndex()).installDefaultEventBus();

public class CustomEventBusIndex implements SubscriberInfoIndex {
    // 保存當前註冊類的 Class 類型和其中事件訂閱方法的信息
    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;

    static {
        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();

        /*
         * 添加訂閱者信息索引——SimpleSubscriberInfo參數:
         * subscriberClass:訂閱者Class類
         * shouldCheckSuperclass:是否檢查父類Class
         * methodInfos(數組):訂閱方法數組
         *
         * SubscriberMethodInfo構造參數:1. 方法名  2. 方法惟一參數類型,即事件類型
         */
        putIndex(new SimpleSubscriberInfo(com.android.framework.launch.activity.EventActivity1.class, true,
                new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onMessageEventPosting", com.android.baselibrary.bean.EventBean.class),
            new SubscriberMethodInfo("onMessageEventMain", com.android.baselibrary.bean.EventBean.class,
                    ThreadMode.MAIN, 2, false),
            new SubscriberMethodInfo("onMessageEventMainOrdered", com.android.baselibrary.bean.EventBean.class,
                    ThreadMode.MAIN_ORDERED),
            new SubscriberMethodInfo("onMessageEventBackground", com.android.baselibrary.bean.EventBean.class,
                    ThreadMode.BACKGROUND),
            new SubscriberMethodInfo("onMessageEventAsync", com.android.baselibrary.bean.EventBean.class,
                    ThreadMode.ASYNC),
        }));

    }

    private static void putIndex(SubscriberInfo info) {
        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
    }

    @Override
    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
        if (info != null) {
            return info;
        } else {
            return null;
        }
    }
}
複製代碼

使用SubscriberInfoIndex時EventBus的註冊流程

  1. 首先看看Application中配置的代碼EventBus.builder().addIndex(new CustomEventBusIndex())
    // EventBusBuilder類:
        public EventBusBuilder addIndex(SubscriberInfoIndex index) {
            if (subscriberInfoIndexes == null) {
                subscriberInfoIndexes = new ArrayList<>();
            }
            subscriberInfoIndexes.add(index);
            return this;
        }
    複製代碼
  2. addIndex把生成的索引類的實例保存在subscriberInfoIndexes集合中,而後用installDefaultEventBus()建立默認的 EventBus實例:
    // EventBusBuilder類:
        public EventBus installDefaultEventBus() {
            synchronized (EventBus.class) {
                if (EventBus.defaultInstance != null) {
                    throw new EventBusException("Default instance already exists." +
                        " It may be only set once before it's used the first time to ensure consistent behavior.");
                }
                // 給默認的EventBus單例對象賦初值
                EventBus.defaultInstance = build();
                return EventBus.defaultInstance;
            }
        }
    
    // EventBus類:  
        public static EventBus getDefault() {
            if (defaultInstance == null) {
                synchronized (EventBus.class) {
                    if (defaultInstance == null) {
                        defaultInstance = new EventBus();
                    }
                }
            }
            return defaultInstance;
        }
    複製代碼
    即用當前EventBusBuilder對象建立一個 EventBus 實例,這樣咱們經過EventBusBuilder配置的 SubscriberInfoIndex 也就傳遞到了EventBus實例中,而後賦值給EventBus的 defaultInstance成員變量。因此在 Application 中生成了 EventBus 的默認單例,這樣就保證了在項目其它地方執行EventBus.getDefault()就能獲得惟一的 EventBus 實例!
  3. subscriberMethodFinder 註解方法找尋器:從第一步addIndex中,咱們知道了subscriberInfoIndexes此時已經不爲null,那麼咱們回到EventBus構造方法中看一個變量:
    EventBus(EventBusBuilder builder) {
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        // @Subscribe註解方法找尋器
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
    }
    
    // 注意此字段
    private List<SubscriberInfoIndex> subscriberInfoIndexes;
    SubscriberMethodFinder(List<SubscriberInfoIndex> subscriberInfoIndexes, boolean strictMethodVerification,
                           boolean ignoreGeneratedIndex) {
        this.subscriberInfoIndexes = subscriberInfoIndexes;
        this.strictMethodVerification = strictMethodVerification;
        this.ignoreGeneratedIndex = ignoreGeneratedIndex;
    }
    複製代碼
    咱們在上面【查找訂閱方法集合】部分提到過一個方法:getSubscriberInfo,此方法默認返回值爲null,所以後面查找訂閱方法爲:運行期經過反射查找。而若配置了Subscriber索引,則getSubscriberInfo返回不爲null:
    // SubscriberMethodFinder類:
        private SubscriberInfo getSubscriberInfo(FindState findState) {
            if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
                SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
                if (findState.clazz == superclassInfo.getSubscriberClass()) {
                    return superclassInfo;
                }
            }
            
            // 上一段代碼中,咱們說過注意此字段,此時不爲null
            if (subscriberInfoIndexes != null) {
                for (SubscriberInfoIndex index : subscriberInfoIndexes) {
                    // 根據註冊類的 Class 類查找SubscriberInfo
                    SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                    if (info != null) {
                        return info;
                    }
                }
            }
            return null;
        }
    
    // index.getSubscriberInfo此方法就是addIndex傳入的 CustomEventBusIndex實現的方法:
        @Override
        public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
            SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
            if (info != null) {
                return info;
            } else {
                return null;
            }
        }
    複製代碼
    所以,findUsingInfo方法中,無需再經過反射單個查找訂閱方法。
    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findState.subscriberInfo = getSubscriberInfo(findState);
            // 此時不爲null
            if (findState.subscriberInfo != null) {
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
                for (SubscriberMethod subscriberMethod : array) {
                    // 檢查添加
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else {
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }
    複製代碼

Subscriber Index 的核心就是項目編譯時使用註解處理器生成保存事件訂閱方法信息的索引類,而後項目運行時將索引類實例設置到 EventBus 中,這樣當註冊 EventBus 時,從索引類取出當前註冊類對應的事件訂閱方法信息,以完成最終的註冊,避免了運行時反射處理的過程,因此在性能上會有質的提升。項目中能夠根據實際的需求決定是否使用 Subscriber Index。異步

參考連接

www.jianshu.com/p/d9516884d…async

juejin.im/post/5db7d7…

blog.csdn.net/lufeng20/ar…

segmentfault.com/a/119000002…

...

注:如有什麼地方闡述有誤,敬請指正。期待您的點贊哦!!!

相關文章
相關標籤/搜索