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