來(lái)點(diǎn)閑白
?EventBus是一款針對(duì)Android優(yōu)化的發(fā)布-訂閱事件總線。它簡(jiǎn)化了應(yīng)用程序內(nèi)各組件間、組件與后臺(tái)線程間的通信。其優(yōu)點(diǎn)是開銷小,代碼更優(yōu)雅,以及將發(fā)送者和接收者解耦。如果Activity和Activity進(jìn)行交互還好說(shuō),但如果Fragment和Fragment進(jìn)行交互則著實(shí)令人頭疼。這時(shí)我們會(huì)使用廣播來(lái)處理,但是使用廣播略嫌麻煩并且效率也不高。如果傳遞的數(shù)據(jù)是實(shí)體類,需要序列化,那么傳遞的成本會(huì)有點(diǎn)高。
進(jìn)入正題
?在講到EventBus的基本用法之前,我們需要了解EventBus的三要素以及它的4種ThreadMode。
EventBus的三要素:
- Event:事件。可以是任意類型的對(duì)象。
- Subscriber:事件訂閱者。在EventBus3.0之前消息處理的方法只能限定于onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,它們分別代表4中線程模型。而在EventBus3.0之后,事件處理的方法可以隨便取名,但是需要添加一個(gè)注解@Subscribe,并且要指定線程模型(默認(rèn)為POSTING)。4種線程模型下面會(huì)講到。
- Publisher:事件發(fā)布者??梢栽谌我饩€程位置發(fā)送事件,直接調(diào)用EventBus的post(Object)方法??梢宰约簩?shí)例化EventBus對(duì)象,但一般使用EventBus.getDefault()就可以。根據(jù)post函數(shù)參數(shù)的類型,會(huì)自動(dòng)調(diào)用訂閱相應(yīng)類型的事件的函數(shù)。
EventBus的4種ThreadMode(線程模型)如下:
- POSTING(默認(rèn)):如果使用事件處理函數(shù)指定了線程模型為POSTING,那么該事件是在那個(gè)線程發(fā)布出來(lái),事件處理函數(shù)就會(huì)在哪個(gè)線程中運(yùn)行,也就是說(shuō)發(fā)布事件和接收事件在同一個(gè)線程中。在線程模型為POSTING的事件處理函數(shù)中盡量避免執(zhí)行耗時(shí)操作,因?yàn)樗鼤?huì)阻塞事件的傳遞,甚至有可能會(huì)引起ANR。
- MAIN:事件的處理會(huì)在UI線程中執(zhí)行。時(shí)間處理的事件不能太長(zhǎng),太長(zhǎng)會(huì)導(dǎo)致ANR。
- BACKGROUND:如果時(shí)間是在UI線程中發(fā)不出來(lái)的,那么該事件處理函數(shù)就會(huì)在新的線程中運(yùn)行;如果事件本來(lái)就是在子線程中發(fā)不出來(lái)的,那么該事件處理函數(shù)直接在發(fā)布事件的線程中執(zhí)行。在此事件處理函數(shù)中禁止進(jìn)行UI更新操作。
- ASYNC:無(wú)論事件在那個(gè)線程中發(fā)布,該事件處理函數(shù)都會(huì)在新建的子線程中執(zhí)行;同樣,此事件處理函數(shù)中禁止UI更新操作。
EventBus基本用法
?EventBus使用起來(lái)分為以下5個(gè)步驟
?(1)自定義一個(gè)事件類型
class MessageEvent{}
?(2)在需要訂閱事件的地方注冊(cè)事件
EventBus.getDefault().register(this);
?(3)發(fā)送事件
EventBus.getDefault().post(messageEvent);
?(4)處理事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun EventMain(messageEvent: MessageEvent){
...
}
?前面說(shuō)過(guò),消息處理的方法可以隨便取名,但是需要添加一個(gè)注解@Subscriber,并且要指定線程模型(默認(rèn)為POSTING)。
?(5)取消時(shí)間訂閱
EventBus.getDefault().unregister(this)
EventBus應(yīng)用
?前面說(shuō)到了EventBus的基本用法,但是這個(gè)過(guò)于簡(jiǎn)單,這里舉個(gè)??來(lái)應(yīng)用EventBus。
?(1)添加依賴庫(kù)
implementation 'org.greenrobot:eventbus:3.1.1'
?(2)定義消息事件類
class MessageEvent(var message: String?)
?(3)注冊(cè)和取消訂閱事件
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn_subscription.setOnClickListener {
EventBus.getDefault().register(this)
Toast.makeText(this, "注冊(cè)事件", Toast.LENGTH_LONG).show()
}
but_message.setOnClickListener {
startActivity(Intent(this, SecondActivity::class.java))
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun EventMain(messageEvent: MessageEvent){
}
override fun onDestroy() {
super.onDestroy()
//取消注冊(cè)事件
EventBus.getDefault().unregister(this)
}
}
?在MainActivity中定義兩個(gè)Button;一個(gè)用來(lái)注冊(cè)事件,另一個(gè)用來(lái)調(diào)轉(zhuǎn)到SecondActivity。
?(4)事件訂閱者處理事件
?在MianActivity中自定義方法來(lái)處理事件,在這里ThreadMode設(shè)置為MAIN,事件會(huì)在UI線程中執(zhí)行,用TextView來(lái)展示收到的時(shí)間消息:
@Subscribe(threadMode = ThreadMode.MAIN)
fun EventMain(messageEvent: MessageEvent){
textView.text = messageEvent.message
}
?(5)事件發(fā)布者發(fā)布事件
?創(chuàng)建了SecondActivity來(lái)發(fā)布消息,代碼所示:
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
btn_send_message.setOnClickListener {
//發(fā)送事件
EventBus.getDefault().post(MessageEvent("歡迎來(lái)到張三兒的簡(jiǎn)書"))
finish()
}
}
}
?在SecondActivity中,我們定義“事件發(fā)送”按鈕來(lái)發(fā)送事件并將SecondActivity finish掉。運(yùn)行程序。如圖所示。接下點(diǎn)擊MainAcitivity中的“注冊(cè)事件”,然后點(diǎn)擊“跳轉(zhuǎn)到SECONDACTIVITY”按鈕,這時(shí)跳轉(zhuǎn)到SecondActivity,如圖所示,接下來(lái)點(diǎn)擊“發(fā)送事件”按鈕,這個(gè)時(shí)候SecondActivity被finish掉,因此界面展示的是MainActivity如圖所示??梢钥吹組ainActivity的TextView顯示“歡迎關(guān)注張三兒的簡(jiǎn)書”,MainActivity成功的接收到了SecondActivity發(fā)送的事件。



?(6)ProGuard
?最后不要忘記在ProGuard中加入混淆規(guī)則:
-keepattributes *Annotation*
-keepclassmembers class **{
@org.greenrobot.eventbus.Subscribe<methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode{*;}
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent{
<init>(java.lang.Throwable);
}
EventBus的黏性事件
?c除了上面講到的普通事件外,EventBus還支持發(fā)送黏性事件,就是在發(fā)送事件之后再訂閱該事件也能收到該事件,這跟黏性廣播類似,為了驗(yàn)證黏性事件,我們修改下以前的代碼。
?(1)訂閱者處理黏性事件
在MainActivity中新寫一個(gè)方法用來(lái)處理黏性事件:
@Subscribe(threadMode = ThreadMode.POSTING,sticky = true)
fun ononMoonStickyEvent(messageEvent: MessageEvent){
textView.text = messageEvent.message
}
?(2)發(fā)送黏性事件
?在SecondActivity中定義一個(gè)Button來(lái)發(fā)送黏性事件:
btn_send_message.setOnClickListener {
//發(fā)送事件
EventBus.getDefault().postSticky(MessageEvent("粘性事件"))
finish()
}
?現(xiàn)在運(yùn)行代碼再來(lái)看看效果,首先,在MianActivity中并沒點(diǎn)擊“注冊(cè)事件”按鈕,而是直接調(diào)轉(zhuǎn)到SecondActivity中點(diǎn)擊發(fā)送“黏性事件”按鈕。這時(shí)界面回到MianActivity,看到TextView依舊顯示著MainActivity的字段,這時(shí)因?yàn)楝F(xiàn)在還沒有訂閱事件。接下來(lái)點(diǎn)擊“注冊(cè)事件”按鈕,TextView內(nèi)容發(fā)生改變,顯示“黏性事件”,說(shuō)明黏性時(shí)間被成功接受到了。