簡讀Eventbus3.0

簡單瞭解一下eventbus的工作情況,學學大神的思想,那麼在此篇文章之前呢,建議大家先要了解清楚何爲註解和反射,如果沒了解,可以先看看前一篇文章,有具體的介紹  Android 註解 (Annotation)

使用過eventbus的都知道,eventbus是一個Android事件發佈/訂閱輕量級框架, 它可以完美的在任何地方完成通信任務,那麼不廢話啦,按照 咱們在Android中的使用過程爲思路展開一個瞭解吧

一、我們是在需要接受事件的地方(例如activity、fragment) 註冊 eventbus事件

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(...);
        //註冊eventbus事件
        EventBus.getDefault().register(this);
     
    }

好啦,如上代碼,我們在activity的oncreate生命週期方法中註冊了eventbus事件,那麼來看一下 getDefault()、register()方法到底幹了點什麼

//第一部分,獲取單例(懶漢式,"懶得創建自己")
public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }


//第二部分,註冊給定的訂閱服務器以接收事件。訂閱者必須調用{unregister(Object)取消註冊(對象)}
public void register(Object subscriber) {
        //1.首先通過反射獲取到當前類
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//2
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);//3
            }
        }
    }

      第一部分 EventBus.getDefault() 是一個懶漢式單例。                                                                              

      第二部分是註冊,1.首先通過當前object.getclass()反射方法獲取到當前 class對象;    2.然後通過 findSubscriberMethods 方法獲取到一個當前class對象的所有方法,並放在一個list集合中,List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); 該行代碼中就是就是維護了 一個 ConcurrentHashMap 對象 ; 3.接下來就是一個 synchronized 同步塊,把該類和該類的多個方法進行配對訂閱

 

二、發送提交和訂閱消費

提交事件到總線:  EventBus.getDefault().post(object);

//將給定事件提交到事件總線
public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get(); //1
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (!postingState.isPosting) {//2
            postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
            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);//3
                }
            } finally { //最終把狀態都還原了
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

//-------------------current Posting Thread State --------------------------

private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };



//------------------Posting Thread State------------------------

/** For ThreadLocal, much faster to set (and get multiple values). */
final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<Object>(); //消息集合
        boolean isPosting; //是否有發送
        boolean isMainThread; //是否是主線程
        Subscription subscription; //訂閱關係
        Object event; //具體發送的事件體
        boolean canceled; //是否取消了
    }

 1. PostingThreadState postingState = currentPostingThreadState.get() 該方法其實就是ThreadLocal對象(線程副本,爲線程本身存儲變量等信息),而PostingThreadState就是線程副本內所存儲JavaBean對象 (在此可以看出,該bean對象並沒有get set封裝),從bean對象中獲取到消息集合,並把當前post所要提交的消息保存在該集合中;

 2. 使用 isposting 來判斷是否發送過信息,然後進入下一步判斷當前發送post方法執行的線程是否是主線程,設置發送狀態,判斷消息是否有效,while遍歷

3. while在集合非空狀態下,會不斷遍歷 postSingleEvent 方法,不斷從集合中獲取消息體和副本中數據進行處理,那麼在往下查看有  postToSubscription(subscription, event, postingState.isMainThread) 這樣的方法,它主要就是獲取咱們標籤中的value,根據不同的value 在不同的線程做不同的操作

//常用的四個標籤
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING://當前線程執行
                invokeSubscriber(subscription, event);
                break;
            case MAIN: //事件的消費會在UI線程。因此,不宜進行耗時操作,以免引起ANR
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case BACKGROUND://背景線程,如果事件在UI線程產生,那麼事件的消費會在單獨的子線程中進行。否則,在同一個線程中消費。
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC://異步執行,不管是否在UI線程產生事件,都會在單獨的子線程中消費事件
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }


//---------------------反射中的 方法執行---------------------------

void invokeSubscriber(Subscription subscription, Object event) {
        try {
            //通過反射獲取到要執行的方法 subscription.subscriber,該方法的參數就是 通過 post要提交的消息
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
            handleSubscriberException(subscription, event, e.getCause());
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception", e);
        }
    }

三、註銷

EventBus.getDefault().unregister(this);

//每個待消費事件的class都會對應一個list集合
private final Map<Object, List<Class<?>>> typesBySubscriber;
//取消註冊
public synchronized void unregister(Object subscriber) {
        //獲取該activity或fragment對應的註解類
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            // 遍歷所有的訂閱方法 ,並取消
            for (Class<?> eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);
            }
            typesBySubscriber.remove(subscriber);
        } else {
            Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }
在使用的時候只是簡單導入eventbus jar,我們調用的時候只要簡單的註冊和配置註解標籤即可,極大提供了開發效率,這就是提供框架的好處;另外重要的一點,就是學習文中的“註冊”與“註銷”的精神,程序做到了有始有終,在開闢了內存,在內存中完成業務,然後在view組件結束生命週期的時候把所佔的內存、操作都結束了       ;初次解讀,有問題的地方要指出,互相提高吧

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章