1. 程式人生 > >EventBus 3.1.1基礎使用和原理解析

EventBus 3.1.1基礎使用和原理解析

EventBus 3.1.1基礎使用和原理淺析

1、簡介

EventBus 是一個 Android 事件釋出/訂閱框架,通過解耦釋出者和訂閱者簡化 Android 事件傳遞。 本文基於EventBus 3.1.1進行事件釋出/訂閱的使用和原理解析。

2、基礎使用

①、新增依賴

compile 'org.greenrobot:eventbus:3.1.1'     

②、註冊 以在Activity中為例:

@Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate
(savedInstanceState); EventBus eb = EventBus.getDefault(); if (!eb.isRegistered(this)) { eb.register(this); } }

③、反註冊 如果註冊了那麼一定要反註冊,否則會導致記憶體洩漏 以在Activity中為例:

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

④、新增接收方法

	//@Subscribe 注入事件接收方法,如果一個activity或者fragment已經註冊了,那麼必須擁有至少一個事件接收方法
	//threadMode = ThreadMode.MAIN 該方法的邏輯在主執行緒中執行,可更改為BackGround使邏輯在後臺執行緒執行
	//onEvent 方法名,可隨意取,不同的activity中的方法名可以重複
	//(Object Event) 唯一標示,假如此處寫(User user),那麼該方法只能接收User型別的訊息
@Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(Object event) { //TODO 接收到訊息後的邏輯 }

⑤、傳送訊息

	//這裡的event的引用型別,就是onEvent接收方法裡Object要明確指定的類
	EventBus.getDefault().post(event);

3、原理淺析

①、register方法

 public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

通過傳入類獲取class物件和subscriberMethods,這裡著重看一下findSubscriberMethodsf()方法

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        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;
        }
    }

這個方法中通過class物件獲取了該class裡所有的事件接收方法,並返回一個List,再來看一下SubscriberMethod這個類

public class SubscriberMethod {
    final Method method;//Method物件,用於反射呼叫
    final ThreadMode threadMode;//事件接收方法內邏輯執行在何種執行緒
    final Class<?> eventType;//事件接收方法接受的形參引用型別
    final int priority;//優先順序
}

在register方法中通過

synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }

將所有的SubscriberMethod封裝為Subscription物件存入subscriptionsByEventType這個Map集合中 ②、post方法

/** Posts the given event to the event bus. */
    public void post(Object event) {
        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;
            }
        }
    }

可以看到該方法最終呼叫了這個方法來執行post

postSingleEvent(eventQueue.remove(0), postingState);

該方法通過呼叫來執行post

postSingleEventForEventType(event, postingState, eventClass);

下面看一看這個方法做了什麼事情

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            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;
    }

可以看到,這個方法通過eventClass從subscriptionsByEventType中獲取了CopyOnWriteArrayList subscriptions集合,並通過迴圈的方式逐一呼叫postToSubscription方法來進行post,那麼在看看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 MAIN_ORDERED:
                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);
        }
    }

這個方法中,發現了invokeSubscriber方法,那麼繼續往下看

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);
        }
    }

這裡就很明顯的可以看見,該方法使用Method物件利用反射直接呼叫訂閱方法,實現了事件訂閱。 ③、效能問題 從以上原理淺析可以得出一個結論 1> 每一次register,EventBus就會把同一個EventType的訂閱方法Method物件存入同一個List集合並放入Map中進行管理。 2> 每次post,都會通過EventType從Map中取出所有List,然後迴圈該List逐一呼叫反射方法進行訊息傳送。 3> 因為反射是比較耗費資源的,所以在定義事件的時候儘量避免無用的呼叫,也就是說盡量細化event。