天天看點

EventBus 線程切換原理

主要問題其實隻有兩個,其一:如何判斷目前發送事件的線程是否是主線程;其二:如何在接收事件時指定線程并執行;

一個一個來看。

1.如何判斷是否在主線程發送

EventBus在初始化的時候會初始化一個MainThreadSupport對象,它會去擷取主線程的Looper對象并存起來。(目前最新版本如果不是Android環境MainThreadSupport會為空,非Android環境也就無需關注是否是UI主線程的問題了)

在發送消息的時候,EventBus會取出目前線程的Looper對象對象與主線程Looper對象做比較,如果相同,說明是在主線程發送消息,如果不同,說明是在子線程發送消息。以下是MainThreadSupport的代碼:

2.怎麼在指定的線程執行訂閱者的方法

在找到訂閱者之後,判斷不同線程情況下執行訂閱方法的邏輯基本都在postToSubscription()方法裡面:

以上代碼中,如何判斷是否是主線程上面已經說過了。

invokeSubscriber()這個方法其實就是拿到訂閱者的資訊,直接執行訂閱方法了(通過反射擷取)。

subscription對象中有一個SubscriberMethod對象,而SubscriberMethod這個對象基本上包含了訂閱者的執行線程、訂閱方法、是否粘性事件、優先級等等資訊。如下:

是以,從postToSubscription()方法可以看出,當threadMode是POSTING時,直接在目前線程執行,不做判斷,也就是從哪個線程發送,就從哪個線程執行訂閱方法;

我們這裡主要來看threadMode為MAIN和BACKGROUND的情況:

在主線程執行

當threadMode為MAIN時,如果在主線程發送,直接在目前線程執行,沒有問題。

如果不在主線程發送,會有一個mainThreadPoster将包含訂閱者資訊的對象加入隊列。這個mainThreadPoster其實是Handler的子類,它利用Handler的消息機制,發送消息并在主線程接收消息,擷取到訂閱者的資訊後在主線程處理事件,進而實作在子線程發送消息,在主線程處理事件。

這裡直接利用Hadler的現成機制,可謂簡明高效。

在子線程執行

當threadMode為BACKGROUND時,如果不在主線程發送,直接執行,沒有問題。

如果在主線程發送,這裡有一個backgroundPoster将包含訂閱者資訊的對象加入隊列。BackgroundPoster其實是Runnable的子類,在自己的run方法中不斷從隊列中取出訂閱者對象,執行訂閱方法。EventBus維護了一個線程池,BackgroundPoster會将自己丢到線程池中,執行自己的run方法,進而實作在在主線程發送事件,在子線程中執行訂閱方法。

以上,就是EventBus切換執行線程的主要流程。

其實并不難。

末尾附上一篇講解EventBus原理的簡練博文:戳這裡

附:EventBus線程切換

轉載于:https://www.cnblogs.com/wytiger/p/10436188.html