面試題之---EventBus原始碼解析
(一)介紹
1,EvenetBus是一種釋出-訂閱事件匯流排.程式碼簡潔,開銷小,並很好的實現了傳送者和接收者的解耦.(是一種觀察者模式)
2,三要素:
A,Event:事件,
B,Publisher:釋出者,可以在任意執行緒釋出事件
C,Subscrible:訂閱者,
3,通常情況下安卓下資料的傳遞有下面幾種方法:
3.1.通過intent傳遞,包括顯式意圖和隱式意圖,廣播(Broadcast)和服務都能通過Intent傳遞
傳遞的資料型別包括8大基本資料型別 實現Parcelable或Serializable介面的型別 以及集合陣列型別
3.2.靜態變數傳遞 在工具類下 宣告一個Object型別的靜態變數 在A中將要傳遞的值,在B中通過這個靜態變數取出來
3.3.通過handle在不同的執行緒中傳遞Object型別的資料
3.4.通過構造方法傳遞Object型別的資料
3.5.通過SharedPreferences傳遞八大基本資料型別
3.6.通過ContentProvider在程序間共享資料
3.7.通過aidl在程序程序傳遞資料
3.8.通過流(本地檔案)傳遞八大基本資料型別和實現Serializable介面的資料型別
3.9.通過基類中的屬性或者方法
屬性: 基類公有屬性 在某個子類中賦值 其他子類中都能使用
方法: 子類呼叫父類的某個方法給父類某個屬性賦值 另外一個子類通過父類的另一個公有方法獲取這個值(這個方法把值返回)
(二)基本使用
##先訂閱,後釋出
- 1,新增依賴
compile 'org.greenrobot:eventbus:3.1.1'
- 2,註冊事件
public class MessageEvent {
private String message;
public MessageEvent(String message){
this.message = message;
}
public String getMessage(){
return message;
}
}
- 3,在接受訊息的程式碼
//註冊成為訂閱者
EventBus.getDefault().register(this);
@Override
protected void onDestroy() {
super.onDestroy();
//解除註冊
EventBus.getDefault().unregister(this);
}
//訂閱方法,當接收到事件的時候,會呼叫該方法
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent messageEvent){
Log.e("date","receive it");
Toast.makeText(ViewPageStep1Activity.this, messageEvent.getMessage(), Toast.LENGTH_SHORT).show();
}
- 4,在傳送訊息的地方
EventBus.getDefault().post(new MessageEvent("從fragment將資料傳遞到activity22222222"));
###先發布,再訂閱,黏性事件
- 5,在接受訊息的程式碼
//註冊成為訂閱者
EventBus.getDefault().register(this);
@Override
protected void onDestroy() {
super.onDestroy();
//解除註冊
EventBus.getDefault().unregister(this);
}
//訂閱方法,當接收到事件的時候,會呼叫該方法
@Subscribe(threadMode = ThreadMode.MAIN,stick = true)
public void onEvent(MessageEvent messageEvent){
Log.e("date","receive it");
Toast.makeText(ViewPageStep1Activity.this, messageEvent.getMessage(), Toast.LENGTH_SHORT).show();
}
- 6,在傳送訊息的地方
EventBus.getDefault().postSticky(new MessageEvent("從fragment將資料傳遞到activity22222222"));
(三)四個訂閱方法
onEvent:
如果使用onEvent作為訂閱函式,那麼該事件在哪個執行緒釋出出來的,onEvent就會在這個執行緒中執行,也就是說釋出事件和接收事件執行緒在同一個執行緒。使用這個方法時,在onEvent方法中不能執行耗時操作,如果執行耗時操作容易導致事件分發延遲。
onEventMainThread:
如果使用onEventMainThread作為訂閱函式,那麼不論事件是在哪個執行緒中釋出出來的,onEventMainThread都會在UI執行緒中執行,接收事件就會在UI執行緒中執行,這個在Android中是非常有用的,因為在Android中只能在UI執行緒中跟新UI,所以在onEvnetMainThread方法中是不能執行耗時操作的。
onEventBackground:
如果使用onEventBackgrond作為訂閱函式,那麼如果事件是在UI執行緒中釋出出來的,那麼onEventBackground就會在子執行緒中執行,如果事件本來就是子執行緒中釋出出來的,那麼onEventBackground函式直接在該子執行緒中執行。
onEventAsync:
使用這個函式作為訂閱函式,那麼無論事件在哪個執行緒釋出,都會建立新的子執行緒在執行onEventAsync。
(四)原始碼解析
可以看到,釋出者(Publisher
)使用post()
方法將Event
傳送到Event Bus
,而後Event Bus
自動將Event
傳送到多個訂閱者(Subcriber
)。這裡需要注意兩個地方:
(1)一個釋出者可以對應多個訂閱者。
(2)3.0以前訂閱者的訂閱方法為onEvent()
、onEventMainThread()
、onEventBackgroundThread()
和onEventAsync()
。在Event Bus3.0
之後統一採用註解@Subscribe
的形式,具體實現方式見下文。
// 1主執行緒呼叫
@Subscribe(threadMode = ThreadMode.MAIN)
public void eventBusMain(String str){
Log.i("TAG", "MAIN:"+str+" Thread="+Thread.currentThread().getId());
}
// 2.釋出執行緒為主執行緒,新開執行緒呼叫
// 2.釋出執行緒為子執行緒,釋出執行緒呼叫
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void eventBusBg(String str){
Log.i("TAG", "BACKGROUND:"+str+" Thread="+Thread.currentThread().getId());
}
//3,哪個執行緒釋出,就在哪個執行緒呼叫
@Subscribe(threadMode = ThreadMode.POSTING)
public void eventBusPosting(String str){
Log.i("TAG", "POSTING:"+str+" Thread="+Thread.currentThread().getId());
}
// 4,每次都新開執行緒呼叫
@Subscribe(threadMode = ThreadMode.ASYNC)
public void eventBusAsync(String str){
Log.i("TAG", "ASYNC:"+str+" Thread="+Thread.currentThread().getId());
}
1,呼叫getDefault(),裡面採用單利雙重鎖模式建立Eventbus物件
static volatile EventBus defaultInstance;
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
2,構造方法
2.1,粘性事件,儲存到ConCurrenHashMap集合,(在構造方法中實現),
HashMap效率高,但執行緒不安全,在多執行緒的情況下,儘量用ConcurrentHashMap,避免多執行緒併發異常
EventBus(EventBusBuilder builder) {
logger = builder.getLogger();
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>(); //執行緒安全,
mainThreadSupport = builder.getMainThreadSupport();
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
logSubscriberExceptions = builder.logSubscriberExceptions;
logNoSubscriberMessages = builder.logNoSubscriberMessages;
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
throwSubscriberException = builder.throwSubscriberException;
eventInheritance = builder.eventInheritance;
executorService = builder.executorService;
}
3,註冊register()方法主要做了2件事:
3.1,找到訂閱者的方法.找出傳進來的訂閱者的所有訂閱方法,然後遍歷訂閱者的方法.
A,通過反射來獲取訂閱者中所有的方法,並根據方法的型別,引數和註解找到訂閱方法.
3.2,訂閱者的註冊
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
//找到訂閱者的方法.找出傳進來的訂閱者的所有訂閱方法,然後遍歷訂閱者的方法.
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//訂閱者的註冊
subscribe(subscriber, subscriberMethod);
}
}
}
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// 通過反射來獲取訂閱者中所有的方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
//
,並根據方法的型別,引數和註解找到訂閱方法.
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;}
//通過CopyOnWriteArrayList儲存Subscription,
//Arraylist效率高,但執行緒不安全,在多執行緒的情況下,使用CopyOnWriteArrayList,避免多執行緒併發異常
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
3,事件傳送post(),
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 {
//處理佇列中的所有事件,
//將所有的事情交給postSingleEvent處理,並移除該事件
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
4,取消事件訂閱
public synchronized void unregister(Object subscriber) {
//typesBySubscriber是一個map集合,
//通過subscriber找到 subscribedTypes (事件型別集合),
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
//將subscriber對應的eventType從typesBySubscriber移除
typesBySubscriber.remove(subscriber);
} else { logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass()); }}
借鑑:劉望舒先生的進階之光