近來在看平凡的世界,一發(fā)不可收拾夯巷,非常震撼心靈,心里面的那種觸動(dòng)我真的表達(dá)不清楚哀墓。已經(jīng)很久沒有看到這么好看的電視劇了趁餐。如果你還沒看過,我推薦大家可以去看一看麸祷。
前段時(shí)間有人問我澎怒,fragment 怎么與 activity 通信?同級(jí)下的 fragment 之間的通信阶牍?
對(duì)于這個(gè)問題有很多方案喷面,我簡單的說幾種,可能還有更好的方案走孽。
宿主 onAttach 方法獲取到 activity 實(shí)例惧辈,有了實(shí)例就是調(diào)用方法的問題了。注意不同的 fragment 之間需要強(qiáng)轉(zhuǎn)磕瓷。
接口
廣播 (有點(diǎn)大題小用了)
handler
EventBus盒齿,RxBus,Otto
五種方案各有優(yōu)缺點(diǎn)困食,在項(xiàng)目當(dāng)中根據(jù)具體情況靈活應(yīng)用边翁。這里主要講解 EventBus 在項(xiàng)目中的使用潦刃,雖然 EventBus 可以很方便的實(shí)現(xiàn)模塊與模塊之間的通信响鹃,如果頻繁的使用可能導(dǎo)致代碼錯(cuò)亂肝陪。這點(diǎn)對(duì)于初學(xué)者尤為重要糙及。下面一起來看看 EventBus 一些常用的使用方法。
什么是EventBus
EventBus是一個(gè) 發(fā)布/訂閱 模式的消息總線庫惋戏,它簡化了應(yīng)用程序內(nèi)各組件間潭苞、組件與后臺(tái)線程間的通信慌随,解耦了事件的發(fā)送者和接收者垛贤,避免了復(fù)雜的焰坪、易于出錯(cuò)的依賴及生命周期問題,可以使我們的代碼更加簡潔聘惦、健壯某饰。EventBus 用于各組件通信,那么用于 fragment 之間的通信就非常合適了。
相關(guān)文章:
EventBus的基本使用
項(xiàng)目依賴
gradle依賴:
在 app
的 build.gradle
文件下:
dependencies {
compile 'org.greenrobot:eventbus:3.0.0'
}
接著來擼一擼 EventBus 的使用步驟:
- 1露乏、 定義事件
- 2碧浊、 訂閱
- 3、 發(fā)布事件
1瘟仿、定義事件
MessageEvent 為例:
public class MessageEvent {
public String message;
public MessageEvent(String message) {
this.message = message;
}
}
訂閱
聲明訂閱方法,并且指定線程模式(默認(rèn)主線程)比勉。
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(this,"你好EventBus"+event.message,Toast.LENGTH_SHORT).show();
};
注意 @Subscribe annotation
是不可缺少的劳较,onMessageEvent
方法名可以隨意命名。
在 activity
或 fragment
注冊(cè)和注銷 EventBus
:
onCreate
注冊(cè):
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
}
onStart
注冊(cè):
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
onDestroy
注銷:
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
發(fā)布事件
最后即是事件源發(fā)布事件浩聋。我們可以在代碼的任何位置發(fā)布事件观蜗,當(dāng)前所有事件類型與發(fā)布的事件類型匹配的訂閱者都將收到它。其實(shí)內(nèi)部是以 map
來存儲(chǔ)事件衣洁,map
的鍵就是事件類名(這里就是MessageEvent
作為鍵值)墓捻,在發(fā)布相同事件源的時(shí)候避免多次處理。
EventBus.getDefault().post(new MessageEvent(""));
下面來看一個(gè)簡單的案例(通過點(diǎn)擊按鈕來發(fā)步事件源):
public void click_event(View view) {
EventBus.getDefault().post(new MessageEvent("雞年大吉"));
}
效果圖一覽:
源碼我會(huì)在文章的最后給出坊夫。
Sticky事件
Sticky
事件被我稱之為粘性事件砖第,功能類似sticky broadcast
(粘性廣播)。就是某些事件攜帶的信息在事件被發(fā)布之后依然有價(jià)值环凿。比如梧兼,當(dāng)前 activity
發(fā)布了事件源,新啟的 activity
對(duì)該事件進(jìn)行訂閱智听,同樣能夠處理羽杰。
發(fā)布粘性事件:
EventBus.getDefault().postSticky(new MessageEvent("大吉大利"));
處理粘性事件:
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(this, "接收A發(fā)來的消息" + event.message, Toast.LENGTH_SHORT).show();
}
注意 sticky
成員設(shè)置為 true
,默認(rèn)為 false
到推。
運(yùn)行效果圖:
源碼會(huì)在文章最后附上
最新的sticky
事件會(huì)在注冊(cè)時(shí)立即自動(dòng)地被傳遞給匹配的訂閱者考赛。但有時(shí)手動(dòng)地去檢查sticky
事件可能會(huì)更方便一些。有時(shí)也可能需要移除(消費(fèi))sticky
事件以便于它不會(huì)再被傳遞莉测。
移除sticky
事件:
MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
if (stickyEvent != null) {
EventBus.getDefault().removeStickyEvent(stickyEvent);
}
查看源碼我們知道removeStickyEvent
方法是重載的颜骤,當(dāng)傳遞class
時(shí),它將返回持有的之前的sticky
事件悔雹。也可以使用如下變體進(jìn)行處理:
MessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);
if (stickyEvent != null) {
//handler
}
優(yōu)先級(jí)
我們可以通過優(yōu)先級(jí)來改變事件傳遞的順序复哆。
@Subscribe(priority = 1)
public void onEvent(MessageEvent event) {
}
在相同的傳遞線程內(nèi)(ThreadMode),優(yōu)先級(jí)越高的訂閱者越先接收到事件腌零。默認(rèn)優(yōu)先級(jí)為0梯找。在不同線程(ThreadMode)中優(yōu)先級(jí)并不會(huì)影響事件的傳遞順序。
取消事件
有時(shí)我們需要取消事件的傳遞:
@Subscribe()
public void onMessageEvent(MessageEvent event) {
//處理事件...
//取消事件
EventBus.getDefault().cancelEventDelivery(event) ;
}
所有后續(xù)的事件傳遞將被取消益涧,后面的訂閱者將無法接收到事件锈锤。cancelEventDelivery
方法只接收(Object event)
參數(shù),那么我們只能在訂閱者的事件處理方法中調(diào)用。
傳遞線程
事件可以在不同于拋出事件的線程中傳遞久免。一個(gè)很常見的例子浅辙,獲取網(wǎng)絡(luò)數(shù)據(jù)更新UI
。網(wǎng)絡(luò)阎姥,耗時(shí)的操作必然是異步操作记舆,更新 UI
則在 UI
線程操作。
EventBus
的傳遞線程類型有四類:
- ThreadMode.POSTING(默認(rèn))
- ThreadMode.MAIN (主線程)
- ThreadMode.BACKGROUND (后臺(tái)線程)
- ThreadMode.ASYNC (異步線程)
ThreadMode.POSTING
默認(rèn)方式呼巴,訂閱者將在與拋出事件相同的線程中被調(diào)用泽腮。事件傳遞是同步完成的,事件傳遞完成時(shí)衣赶,所有的訂閱者將已經(jīng)被調(diào)用了一次诊赊。這個(gè)ThreadMode
意味著最小的開銷,因?yàn)樗耆苊饬司€程的切換府瞄。鑒于以上的特點(diǎn)碧磅,那么可以用于已知耗時(shí)非常短的簡單的不需要請(qǐng)求主線程的任務(wù),可以采用該模式遵馆。使用這個(gè)模式的事件處理器應(yīng)該迅速返回以避免阻塞發(fā)布事件的線程鲸郊,而后者可能是主線程。比如:
@Subscribe(threadMode = ThreadMode.POSTING)
public void onMessage(MessageEvent event) {
//handler事件
Toast.makeText(this, "你好EventBus" + event.message, Toast.LENGTH_SHORT).show();
}
ThreadMode.MAIN
訂閱者將在主線程(UI線程)中被調(diào)用团搞。如果發(fā)布事件的線程是主線程严望,事件處理器方法將會(huì)直接被調(diào)用。事件處理器使用這個(gè)模式必須快速地返回以避免阻塞主線程逻恐。
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(MessageEvent event) {
//處理事件
}
ThreadMode.BACKGROUND
訂閱者將在一個(gè)后臺(tái)線程中被調(diào)用像吻。如果發(fā)布事件的線程不是主線程,事件處理器方法將在該線程中被調(diào)用复隆;反之拨匆,EventBus
使用一個(gè)單獨(dú)的后臺(tái)線程,它將順序地傳遞它所有的事件挽拂。使用該模式的事件處理器應(yīng)該嘗試快速返回以避免阻塞后臺(tái)線程惭每。
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessage(MessageEvent event) {
//handler事件
}
ThreadMode.ASYNC
訂閱者將在另外一個(gè)線程中被調(diào)用。這里的另外一個(gè)線程不等同于發(fā)布事件的線程和UI
線程亏栈。用于處理比較耗時(shí)的操作台腥,如訪問網(wǎng)絡(luò),數(shù)據(jù)庫操作绒北。
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessage(MessageEvent event) {
//handler事件
}
EventBus
原理這里就不在深入黎侈,EventBus
真的非常棒,值得你擁有闷游。