時間過得很快,轉眼迎來了清明小長假,在小長假到來前期搞定了一個問題,心裡還是很高興的,這裡分享給大家,希望大家遇到相同問題時能有有所幫助。
先說一下我的需求吧,在手頭的項目裡有這麼一個需求,就是一個activity,它有三個fragment,activity要通過網絡從服務端擷取資料,然後分發給三個fragment展示。
最初,我是想用broadcastReceiver實作的,但是寫了一堆代碼以後發現不是想象的那麼簡單。當activity擷取到資料後發送廣播,此時FragmentA和FragmentB已經初始化完畢,當然也完成了BroadcastReceiver的注冊,這兩個是可以接受到activity傳遞過來的資料的,但是FragmentC就尴尬了,在activity發送廣播的時候它還沒有初始化,也就沒有注冊廣播接收器,自然也就沒有資料展示了。這個問題讓我很是頭大了一會兒,後來考慮的用一下EventBus試試,結果一試還真成了,哈哈哈哈,先讓我笑幾聲,然後在這裡記錄一下EventBus的使用吧。
首先,添加依賴庫:
Androidstudio的gradle配置如下:
compile 'org.greenrobot:eventbus:3.0.0'
然後,定義一個MessageEvent類:
public class MessageEvent {
private String message;
public MessageEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
第三,在三個Fragment中注冊、訂閱事件:
public class FragmentA extends Fragment {
private static final String TAG = "FragmentA";
private TextView tvAAA;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_aa,container,false);
tvAAA=view.findViewById(R.id.text_a);
Log.d(TAG, "onCreateView: ");
//注冊
EventBus.getDefault().register(this);
return view;
}
@Override
public void onDestroyView() {
super.onDestroyView();
Log.d(TAG, "onDestroyView: ");
//登出
EventBus.getDefault().unregister(this);
}
}
第四,事件訂閱者處理事件。這裡多說幾句,如果是普通的事件,無法實作剛開始說的事件先發送,後注冊擷取的效果,是以這裡使用的是EventBus 的 黏性事件,這個可以非常好的達到我們的要求。
//事件訂閱者處理事件,必須有此方法
//這裡我們的ThreadMode設定為MAIN,事件的處理會在UI線程中執行,用TextView來展示收到的事件消息
//注意,這裡的注解裡必須有sticky,并将值設定為true,表示與事件綁定,可以在事件已經發送但是還沒有注冊的情況下,一旦注冊,就可以接受到資料
@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
public void onResult(MessageEvent messageEvent){
tvAAA.setText(messageEvent.getMessage());
}
最後,發送黏性事件:
private void sendMsg() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
runOnUiThread(new Runnable() {
@Override
public void run() {
EventBus.getDefault().postSticky(new MessageEvent("here is activity"));
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
簡單的幾行代碼就實作了我們的要求是不是感覺so easy,不過效果雖然實作了,但是我們真正懂得了EventBus了嗎,未必!下面大概了解一下EventBus:
EventBus的三要素
EventBus有三個主要的元素需要我們先了解一下:
- Event:事件,可以是任意類型的對象。
- Subscriber:事件訂閱者,在EventBus3.0之前消息處理的方法隻能限定于onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,他們分别代表四種線程模型。而在EventBus3.0之後,事件處理的方法可以随便取名,但是需要添加一個注解@Subscribe,并且要指定線程模型(預設為POSTING),四種線程模型下面會講到。
- Publisher:事件釋出者,可以在任意線程任意位置發送事件,直接調用EventBus的post(Object)方法。可以自己執行個體化EventBus對象,但一般使用EventBus.getDefault()就好了,根據post函數參數的類型,會自動調用訂閱相應類型事件的函數。
EventBus的四種ThreadMode(線程模型)
EventBus3.0有以下四種ThreadMode:
- POSTING(預設):如果使用事件處理函數指定了線程模型為POSTING,那麼該事件在哪個線程釋出出來的,事件處理函數就會在這個線程中運作,也就是說釋出事件和接收事件在同一個線程。線上程模型為POSTING的事件處理函數中盡量避免執行耗時操作,因為它會阻塞事件的傳遞,甚至有可能會引起ANR。
-
MAIN:
事件的處理會在UI線程中執行。事件處理時間不能太長,長了會ANR的。
- BACKGROUND:如果事件是在UI線程中釋出出來的,那麼該事件處理函數就會在新的線程中運作,如果事件本來就是子線程中釋出出來的,那麼該事件處理函數直接在釋出事件的線程中執行。在此事件處理函數中禁止進行UI更新操作。
- ASYNC:無論事件在哪個線程釋出,該事件處理函數都會在建立的子線程中執行,同樣,此事件處理函數中禁止進行UI更新操作。
好了,就記錄這麼多吧,學海無涯!!!