EventBus3.0以后使用了注解模式,接收消息的方法名可以讓你任性的寫寫寫状您,不再是以onEvent開頭了勒叠,增加了可讀性兜挨,用著更爽了。那么我們?cè)诎岽u的時(shí)候怎么去愉快的使用呢眯分?
磚家認(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、首先需要寫好注冊(cè)與注銷方法:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main)疚察;
//注冊(cè)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)行的線程,還有一個(gè)priority設(shè)置接收消息的優(yōu)先級(jí)
根據(jù)type的值去區(qū)分不同的發(fā)送和接收该溯。
3岛抄、發(fā)送消息:
發(fā)送消息可以分兩種:
一、粘性消息
@Subscribe(sticky = true,threadMode = ThreadMode.MAIN)
sticky 為true的時(shí)候就是粘性消息狈茉,什么是粘性消息呢夫椭?就是EventBus可以先出消息體,然后在EventBus進(jìn)行注冊(cè)的時(shí)候從粘性消息隊(duì)列中取出消息氯庆,進(jìn)行接收,可用于替代intent傳值蹭秋。
發(fā)送方法使用:
EventBus.getDefault().postSticky(new EventMessage<String>(1,"來(lái)自第一世界的消息"));
注意:如果需要接收粘性消息后操作界面,那么threadMode = ThreadMode.MAIN設(shè)為主線程堤撵,而且EventBus注冊(cè)必須在界面初始化之后進(jìn)行仁讨,因?yàn)檎承韵⒃贓ventBus注冊(cè)的時(shí)候被接收。
二实昨、普通消息
普通消息洞豁,只能先注冊(cè)后接收。發(fā)出的消息荒给,只能注冊(cè)過(guò)的EventBus進(jìn)行接收丈挟。用于替代Handler+Message
使用方法:
EventBus.getDefault().post(new EventMessage<String>(2,"來(lái)自第二世界的消息"));
two step :下面介紹EventBus的原理。
源碼大家可以根據(jù)原理自己觀摩學(xué)習(xí)志电,對(duì)于磚家曙咽,你可以直接搬磚使用,但學(xué)習(xí)源碼挑辆,能讓你更懂得如何搬磚桐绒。各人自由發(fā)揮吧夺脾。
1、想成為訂閱者茉继,需要進(jìn)行注冊(cè)
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為訂閱這個(gè)事件的所有訂閱者的CopyOnWriteArrayList
subscriptionsByEventType = new HashMap<>();
//以訂閱者的類為key,以event事件類為value派撕,在進(jìn)行register或unregister的時(shí)候婉弹,會(huì)操作這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);
}
}
}
注冊(cè)的時(shí)候通過(guò)subscriberMethodFinder的findSubscriberMethods方法去查找和緩存訂閱者訂閱了哪些事件.返回一個(gè)SubscriberMethod(SubscriberMethod里包含了這個(gè)方法的Method對(duì)象,以及將來(lái)響應(yīng)訂閱是在哪個(gè)線程的ThreadMode,以及訂閱的事件類型eventType,以及訂閱的優(yōu)先級(jí)priority,以及是否接收粘性sticky事件的boolean值)對(duì)象的List终吼。
接著回到subscribe(subscriber, subscriberMethod)中去,通過(guò)這個(gè)方法,我們就完成了注冊(cè)镀赌。具體代碼自行去觀摩吧。
2际跪、事件的發(fā)送Post
/** Posts the given event to the event bus. */
public void post(Object event) {
//獲取當(dāng)前線程信息
//currentPostingThreadState是一個(gè)ThreadLocal
//ThreadLocal 是一個(gè)線程內(nèi)部的數(shù)據(jù)存儲(chǔ)類商佛,通過(guò)它可以在指定的線程中存儲(chǔ)數(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ā)送單個(gè)事件
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
大致原理是通過(guò)ThreadLocal存儲(chǔ)指定線程的數(shù)據(jù)姆打,數(shù)據(jù)在當(dāng)前線程中的事件隊(duì)列中不停往外分發(fā)良姆。
磚家說(shuō)句話
EventBus先介紹到這,還有很多細(xì)節(jié)沒(méi)有深入幔戏,大家各自去看吧玛追。我們搬磚的時(shí)候首先得學(xué)會(huì)使用,解決工作中的問(wèn)題闲延,然后有空再去觀摩下源碼痊剖,學(xué)習(xí)學(xué)習(xí)。要想看懂這個(gè)源碼垒玲,要會(huì)數(shù)據(jù)結(jié)構(gòu)邢笙、設(shè)計(jì)模式、java注解與反射等侍匙。所以啊氮惯,基礎(chǔ)要牢靠,滴滴滴想暗,走起吧8竞埂!说莫!
demo下載地址:
http://pan.baidu.com/s/1i5DUcML
要想看源碼杨箭,也可參考如下文章,寫的不錯(cuò):
http://www.reibang.com/p/f057c460c77e