天天看點

android EventBus源碼原理分析

本文的源碼使用到EventBus3.2.0版本

本文所示的源碼将會忽略與核心邏輯無關的代碼,被忽略的代碼将使用省略号表示

以下為eventBus最簡單的使用代碼:

public class TestActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    	//	注冊eventbus
        EventBus.getDefault().register(this);.
        //	發送消息
        EventBus.getDefault().post(new Object());
	}
	
	//	添加消息監聽注解
	@Subscribe()
    public void onEvent(Event event){
        Log.d("test","接收到消息");
    }
}
           

該代碼運作後将會列印,“接收到消息”;

EventBus注冊原理

那麼接下來分析代碼“EventBus.getDefault().register(this)”,幹了什麼

public void register(Object subscriber) {
    	//	擷取訂閱者的class對像
        Class<?> subscriberClass = subscriber.getClass();
        // 擷取所有帶有注解“@Subscribe”的方法
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        ...
    }
           

我們繼續進入“subscriberMethodFinder.findSubscriberMethods(subscriberClass)”方法中:

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
		...
        if (ignoreGeneratedIndex) {
        	//預設走這裡
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            subscriberMethods = findUsingInfo(subscriberClass);
        }
        ....
    }
    
    // 命名知意,使用反射方式查找
    private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
       ...
            findUsingReflectionInSingleClass(findState);
        ...
        return getMethodsAndRelease(findState);
    }
    
    private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        ...
        // 擷取訂閱者對象的所有方法
        methods = findState.clazz.getDeclaredMethods();
        ...
         //周遊所有方法
        for (Method method : methods) {
           ...
             	// 核心!核心!核心!
                Class<?>[] parameterTypes = method.getParameterTypes();
                // 過濾隻有一個參數的方法
                if (parameterTypes.length == 1) {
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                   // 找出帶有“Subscribe”注解的方法
                    if (subscribeAnnotation != null) {
                        Class<?> eventType = parameterTypes[0];
                        if (findState.checkAdd(method, eventType)) {
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            // 建立一個訂閱者方法對象,并緩存到subscriberMethods隊列中
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                    subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
                } 
		...
        }
    }
           

好了,簡單來說,EventBus注冊其實就是找出被注冊對象中所有帶有@Subscribe注解的方法,并緩存起來!

EventBus發送消息原理

我們一起來看看 "EventBus.getDefault().post(new Object())"幹了什麼

public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        // 将消息加入到隊列中
        eventQueue.add(event);
        ...
          while (!eventQueue.isEmpty()) {
          		// 周遊隊列,并執行postSingleEvent
                postSingleEvent(eventQueue.remove(0), postingState);
            }
		...
        }
    }

	private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
		// 擷取event的class對象,本事例是Object,實際使用将會是自定義的一個實體類
        Class<?> eventClass = event.getClass();
        ... //剔除了所有非核心代碼
        // lookupAllEventTypes方法實際是找出event對象的所有基類,這裡不多介紹,有興趣的自己跟源碼
         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);
         }
         ...
    }	
	// 核心!核心!核心
   private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
          // 根據event對象,擷取所有訂閱者方法
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
        	//周遊
            for (Subscription subscription : subscriptions) {
				...
                    postToSubscription(subscription, event, postingState.isMainThread);
                ...
            }
            return true;
        }
        return false;
    }
    
	private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
		// 忽略各種線程排程代碼
		   ...
	            invokeSubscriber(subscription, event);
	       ...
	    }
    
	//最終到這裡
    void invokeSubscriber(Subscription subscription, Object event) {
       	...
       		// 反射執行訂閱者的方法,并傳遞event對象
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
		...
    }
           

是以,簡單來說,EventBus消息發送就是通過event對象找出在注冊時所緩存的訂閱者方法,然後執行!

原理總結

一句話,注冊就是以反射方式緩存訂閱者方法,發送消息就是以反射方式執行已緩存的訂閱者方法。

核心實作原理僅用到Java反射機制!

OK,就這麼多!用幫助的話,點個贊!