EventBus是greenrobot再Android平臺發佈的以訂閱-發佈模式爲核心的開源庫。
EventBus翻譯過來是事件總線意思。能夠這樣理解:一個個(event)發送到總線上,
而後EventBus根據已註冊的訂閱者(subscribers)來匹配相應的事件,進而把事件傳遞給訂閱者,
這也是觀察者模式的一個最佳實踐。android
咱們日常開發中,當遇到Activity與Activity、Activity與Fragment之間的通訊,每每採用intent,又
或者線程之間用Handler進行通訊,這樣代碼會複雜不少,而使用EventBus極大簡化兩個組件之間俺的通訊問題,
並且效率極高。而EventBus升級到3.0版本後,開發者可以自定義訂閱方法名字,而不必
規定以「o'n'Event'XX"開頭的方法了,這樣也自由化了不少,並且支持了粘性事件的分發等,所以學會使用EventBus3.0
對咱們開發又極大的好處.
app
activity_mainide
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/tv_text" android:textSize="20sp" android:text="@string/app_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="點擊打開新的Activity" android:id="@+id/secondActivityBtn" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="75dp" /> </RelativeLayout>
activity_second函數
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center"> <EditText android:id="@+id/et" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="請輸入要發送的消息" /> <Button android:id="@+id/sendMessageBtn" android:text="發送消息" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
public class MainActivity extends Activity { private TextView textView; private Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //註冊成爲訂閱者 EventBus.getDefault().register(this); textView = (TextView) findViewById(R.id.tv_text); button = (Button) findViewById(R.id.secondActivityBtn); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this, SecondActivity.class); startActivity(intent); } }); } //訂閱方法,當接收到事件的時候,會調用該方法 @Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(MessageEvent messageEvent){ Log.d("cylog","receive it"); textView.setText(messageEvent.getMessage()); Toast.makeText(MainActivity.this, messageEvent.getMessage(), Toast.LENGTH_SHORT).show(); } @Override protected void onDestroy() { super.onDestroy(); //解除註冊 EventBus.getDefault().unregister(this); } }
public class SecondActivity extends Activity { private EditText et; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); et = findViewById(R.id.et); Button button = (Button) findViewById(R.id.sendMessageBtn); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(TextUtils.isEmpty(et.getText().toString())){ Toast.makeText(SecondActivity.this, "請輸入......", Toast.LENGTH_SHORT).show(); return; }else { EventBus.getDefault().post(new MessageEvent(et.getText().toString())); finish(); } } }); } }
上面示例代碼所說的狀況是:當發送消息推送者推送消息的時候,訂閱者會立馬收到消息,它會把消息推送給它全部的訂閱者.注意後面這句話:若是你但願在消息推送完成以後,讓新註冊的訂閱者也能收到這條消息,這時候你能夠試試Sticky Events,這個事件就像一個常駐廣播,只要是有新的訂閱者訂閱了這個事件,就會收到消息.固然,有兩點要求:佈局
1.首先,發送的是黏性事件,代碼將post改成postStickypost
// EventBus.getDefault().post(new MessageEvent()); EventBus.getDefault().postSticky(new MessageEvent());
2.而後,訂閱者要聲明本身可以接收到黏性事件的消息:代碼中@Subscribe註解中的sticky值爲true,知足了這兩點,就能愉快的玩耍了.測試
@Subscribe(sticky = true) public void onMessageEvent(MessageEvent event) { Log.i(TAG, "onMessageEvent: 我是sticky event 收到消息"); }
3.測試效果
把項目入口調整爲ThridActivitythis
public class ThirdActivity extends Activity implements View.OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_third); Button button1 = (Button) findViewById(R.id.sendStickyMessageBtn1); Button button2 = (Button) findViewById(R.id.sendStickyMessageBtn2); Button button3 = (Button) findViewById(R.id.sendStickyMessageBtn3); Button button4 = (Button) findViewById(R.id.sendRegisterBtn); button1.setOnClickListener(this); button2.setOnClickListener(this); button3.setOnClickListener(this); button4.setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.sendStickyMessageBtn1: EventBus.getDefault().postSticky(new MessageEvent("粘性事件1")); Log.e("cylog","發送粘性事件1..."); break; case R.id.sendStickyMessageBtn2: EventBus.getDefault().postSticky(new MessageEvent("粘性事件2")); Log.e("cylog", "發送粘性事件2..."); break; case R.id.sendStickyMessageBtn3: EventBus.getDefault().postSticky(new MessageEvent("粘性事件3")); Log.e("cylog", "發送粘性事件3..."); break; case R.id.sendRegisterBtn: Log.e("cylog", "註冊成爲訂閱者..."); EventBus.getDefault().register(this); break; } } @Subscribe(sticky = true) public void onEvent(MessageEvent messageEvent){ Log.e("cylog","接受到了來自EventBus的事件:"+messageEvent.getMessage()); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); } }
那麼很明顯,只會接受到最後發送的粘性事件,在此以前的事件都接收不到。線程
在EventBus的事件處理函數中須要指定線程模型,即指定事件處理函數運行所在的想線程。在上面咱們已經接觸到了EventBus的四種線程模型。那他們有什麼區別呢?
在EventBus中的觀察者一般有四種線程模型,分別是PostThread(默認)、MainThread、BackgroundThread與Async。翻譯
PostThread:若是使用事件處理函數指定了線程模型爲PostThread,那麼該事件在哪一個線程發佈出來的,事件處理函數就會在這個線程中運行,也就是說發佈事件和接收事件在同一個線程。在線程模型爲PostThread的事件處理函數中儘可能避免執行耗時操做,由於它會阻塞事件的傳遞,甚至有可能會引發ANR。
MainThread:若是使用事件處理函數指定了線程模型爲MainThread,那麼不論事件是在哪一個線程中發佈出來的,該事件處理函數都會在UI線程中執行。該方法能夠用來更新UI,可是不能處理耗時操做。
BackgroundThread:若是使用事件處理函數指定了線程模型爲BackgroundThread,那麼若是事件是在UI線程中發佈出來的,那麼該事件處理函數就會在新的線程中運行,若是事件原本就是子線程中發佈出來的,那麼該事件處理函數直接在發佈事件的線程中執行。在此事件處理函數中禁止進行UI更新操做。
Async:若是使用事件處理函數指定了線程模型爲Async,那麼不管事件在哪一個線程發佈,該事件處理函數都會在新建的子線程中執行。一樣,此事件處理函數中禁止進行UI更新操做。
爲了驗證以上四個方法,別人的例子
@Subscribe(threadMode = ThreadMode.PostThread) public void onMessageEventPostThread(MessageEvent messageEvent) { Log.e("PostThread", Thread.currentThread().getName()); } @Subscribe(threadMode = ThreadMode.MainThread) public void onMessageEventMainThread(MessageEvent messageEvent) { Log.e("MainThread", Thread.currentThread().getName()); } @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onMessageEventBackgroundThread(MessageEvent messageEvent) { Log.e("BackgroundThread", Thread.currentThread().getName()); } @Subscribe(threadMode = ThreadMode.Async) public void onMessageEventAsync(MessageEvent messageEvent) { Log.e("Async", Thread.currentThread().getName()); }
分別使用上面四個方法訂閱同一事件,打印他們運行所在的線程。首先咱們在UI線程中發佈一條MessageEvent的消息,看下日誌打印結果是什麼。
findViewById(R.id.send).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e("postEvent", Thread.currentThread().getName()); EventBus.getDefault().post(new MessageEvent()); } });
從日誌打印結果能夠看出,若是在UI線程中發佈事件,則線程模型爲PostThread的事件處理函數也執行在UI線程,與發佈事件的線程一致。線程模型爲Async的事件處理函數執行在名字叫作pool-1-thread-1的新的線程中。而MainThread的事件處理函數執行在UI線程,BackgroundThread的時間處理函數執行在名字叫作pool-1-thread-2的新的線程中。
咱們再看看在子線程中發佈一條MessageEvent的消息時,會有什麼樣的結果。
從日誌打印結果能夠看出,若是在子線程中發佈事件,則線程模型爲PostThread的事件處理函數也執行在子線程,與發佈事件的線程一致(都是Thread-125)。BackgroundThread事件模型也與發佈事件在同一線程執行。Async則在一個名叫pool-1-thread-1的新線程中執行。MainThread仍是在UI線程中執行。
上面一個例子充分驗證了指定不一樣線程模型的事件處理方法執行所在的線程。