02-EventBus玩轉(zhuǎn)消息傳遞

EventBus3.0以后使用了注解模式,接收消息的方法名可以讓你任性的寫寫寫,不再是以onEvent開頭了,增加了可讀性,用著更爽了。那么我們在搬磚的時候怎么去愉快的使用呢?

磚家認(rèn)為可以在Activity與Activity、Activity與Fragment、線程之間愉快的傳遞數(shù)據(jù),還可以替代intent傳值,還不用去寫序列化,臥槽,爽炸天有木有。

官網(wǎng)地址:
EventBus GitHub地址
在Android Studio中添加如下依賴即可使用:

compile 'org.greenrobot:eventbus:3.0.0'

one step :下面介紹下使用方法

1、首先需要寫好注冊與注銷方法:

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //注冊EventBus
        EventBus.getDefault().register(this);
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //注銷EventBus
        EventBus.getDefault().unregister(this);
    }

2、碼好接收消息的方法:

自定義消息實(shí)體EventMessage,data使用泛型,可以接收任意類型的數(shù)據(jù)

public class EventMessage<T> {
    private int type;
    private T data;

    public EventMessage(int type, T data) {
        this.type = type;
        this.data = data;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}
 /**
     * 接收消息
     * @param msg
     */
    @Subscribe(sticky = true,threadMode = ThreadMode.MAIN)
    public void eventComing(EventMessage<String> msg){
        if(msg.getType() == 2){
            tv_content.setText(msg.getData());
        }
    }

sticky 設(shè)置是否接收粘性消息,threadMode 設(shè)置運(yùn)行的線程,還有一個priority設(shè)置接收消息的優(yōu)先級
根據(jù)type的值去區(qū)分不同的發(fā)送和接收。

3、發(fā)送消息:

發(fā)送消息可以分兩種:
一、粘性消息

 @Subscribe(sticky = true,threadMode = ThreadMode.MAIN)

sticky 為true的時候就是粘性消息,什么是粘性消息呢?就是EventBus可以先出消息體,然后在EventBus進(jìn)行注冊的時候從粘性消息隊(duì)列中取出消息,進(jìn)行接收,可用于替代intent傳值。
發(fā)送方法使用:

EventBus.getDefault().postSticky(new EventMessage<String>(1,"來自第一世界的消息"));

注意:如果需要接收粘性消息后操作界面,那么threadMode = ThreadMode.MAIN設(shè)為主線程,而且EventBus注冊必須在界面初始化之后進(jìn)行,因?yàn)檎承韵⒃贓ventBus注冊的時候被接收。

二、普通消息
普通消息,只能先注冊后接收。發(fā)出的消息,只能注冊過的EventBus進(jìn)行接收。用于替代Handler+Message
使用方法:

EventBus.getDefault().post(new EventMessage<String>(2,"來自第二世界的消息"));

two step :下面介紹EventBus的原理。

源碼大家可以根據(jù)原理自己觀摩學(xué)習(xí),對于磚家,你可以直接搬磚使用,但學(xué)習(xí)源碼,能讓你更懂得如何搬磚。各人自由發(fā)揮吧。
1、想成為訂閱者,需要進(jìn)行注冊

EventBus.getDefault().register(this);

那么先從getDefault()方法走起,定睛一看,so easy,老司機(jī)都懂,不解釋。

public static EventBus getDefault() {
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
            if (defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}

獲取實(shí)例直接調(diào)用了EventBus構(gòu)造方法

   public EventBus() {
        this(DEFAULT_BUILDER);
    }

    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    private final Map<Object, List<Class<?>>> typesBySubscriber;
    private final Map<Class<?>, Object> stickyEvents;

    private final HandlerPoster mainThreadPoster;
    private final BackgroundPoster backgroundPoster;
    private final AsyncPoster asyncPoster;
    EventBus(EventBusBuilder builder) {
        //key為訂閱事件  value為訂閱這個事件的所有訂閱者的CopyOnWriteArrayList
        subscriptionsByEventType = new HashMap<>();
       //以訂閱者的類為key,以event事件類為value,在進(jìn)行register或unregister的時候,會操作這HashMap。
        typesBySubscriber = new HashMap<>();
        //粘性事件的集合
        stickyEvents = new ConcurrentHashMap<>();
        //事件處理
        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
        backgroundPoster = new BackgroundPoster(this);
        asyncPoster = new AsyncPoster(this);
        ......
    }

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

注冊的時候通過subscriberMethodFinder的findSubscriberMethods方法去查找和緩存訂閱者訂閱了哪些事件.返回一個SubscriberMethod(SubscriberMethod里包含了這個方法的Method對象,以及將來響應(yīng)訂閱是在哪個線程的ThreadMode,以及訂閱的事件類型eventType,以及訂閱的優(yōu)先級priority,以及是否接收粘性sticky事件的boolean值)對象的List。

接著回到subscribe(subscriber, subscriberMethod)中去,通過這個方法,我們就完成了注冊。具體代碼自行去觀摩吧。


2、事件的發(fā)送Post

/** Posts the given event to the event bus. */
    public void post(Object event) {
        //獲取當(dāng)前線程信息
        //currentPostingThreadState是一個ThreadLocal
        //ThreadLocal 是一個線程內(nèi)部的數(shù)據(jù)存儲類,通過它可以在指定的線程中存儲數(shù)據(jù),
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        //把事件加入線程隊(duì)列中
        eventQueue.add(event);
        if (!postingState.isPosting) {
            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()) {
                    //不斷從隊(duì)列中獲取發(fā)送單個事件
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

大致原理是通過ThreadLocal存儲指定線程的數(shù)據(jù),數(shù)據(jù)在當(dāng)前線程中的事件隊(duì)列中不停往外分發(fā)。


磚家說句話

EventBus先介紹到這,還有很多細(xì)節(jié)沒有深入,大家各自去看吧。我們搬磚的時候首先得學(xué)會使用,解決工作中的問題,然后有空再去觀摩下源碼,學(xué)習(xí)學(xué)習(xí)。要想看懂這個源碼,要會數(shù)據(jù)結(jié)構(gòu)、設(shè)計(jì)模式、java注解與反射等。所以啊,基礎(chǔ)要牢靠,滴滴滴,走起吧!?。?/p>

demo下載地址:
http://pan.baidu.com/s/1i5DUcML

要想看源碼,也可參考如下文章,寫的不錯:
http://www.itdecent.cn/p/f057c460c77e

http://www.itdecent.cn/p/bda4ed3017ba

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容