【回復「1024」,送你一個特別推送】
EventBus是一款針對Android優化的發布/訂閱(publish/subscribe)事件總線。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,線程之間傳遞消息。簡化了應用程式內各組件間、組件與後臺線程間的通信。優點是開銷小,代碼更優雅。以及將發送者和接收者解耦。比如請求網絡,等網絡返回時通過Handler或Broadcast通知UI,兩個Fragment之間需要通過Listener通信,這些需求都可以通過EventBus實現。
EventBus作為一個消息總線,有三個主要的元素:
Event:事件。可以是任意類型的對象
Subscriber:事件訂閱者,接收特定的事件。在EventBus中,使用約定來指定事件訂閱者以簡化使用。即所有事件訂閱都都是以onEvent開頭的函數,具體來說,函數的名字是onEvent,onEventMainThread,onEventBackgroundThread,onEventAsync這四個,這個和ThreadMode(下面講)有關。
Publisher:事件發布者,用於通知 Subscriber 有事件發生。可以在任意線程任意位置發送事件,直接調用eventBus.post(Object) 方法,可以自己實例化 EventBus 對象,但一般使用默認的單例就好了:EventBus.getDefault(), 根據post函數參數的類型,會自動調用訂閱相應類型事件的函數。
前面說了,Subscriber的函數只能是那4個,因為每個事件訂閱函數都是和一個ThreadMode相關聯的,ThreadMode指定了會調用的函數。有以下四個ThreadMode:
PostThread:事件的處理在和事件的發送在相同的進程,所以事件處理時間不應太長,不然影響事件的發送線程,而這個線程可能是UI線程。對應的函數名是onEvent。
MainThread: 事件的處理會在UI線程中執行。事件處理時間不能太長,這個不用說的,長了會ANR的,對應的函數名是onEventMainThread。
BackgroundThread:事件的處理會在一個後臺線程中執行,對應的函數名是onEventBackgroundThread,雖然名字是BackgroundThread,事件處理是在後臺線程,但事件處理時間還是不應該太長,因為如果發送事件的線程是後臺線程,會直接執行事件,如果當前線程是UI線程,事件會被加到一個隊列中,由一個線程依次處理這些事件,如果某個事件處理時間太長,會阻塞後面的事件的派發或處理。
Async:事件處理會在單獨的線程中執行,主要用於在後臺線程中執行耗時操作,每個事件會開啟一個線程(有線程池),但最好限制線程的數目。
根據事件訂閱都函數名稱的不同,會使用不同的ThreadMode,比如果在後臺線程加載了數據想在UI線程顯示,訂閱者只需把函數命名onEventMainThread。
onEvent:如果使用onEvent作為訂閱函數,那麼該事件在哪個線程發布出來的,onEvent就會在這個線程中運行,也就是說發布事件和接收事件線程在同一個線程。使用這個方法時,在onEvent方法中不能執行耗時操作,如果執行耗時操作容易導致事件分發延遲。
onEventMainThread:如果使用onEventMainThread作為訂閱函數,那麼不論事件是在哪個線程中發布出來的,onEventMainThread都會在UI線程中執行,接收事件就會在UI線程中運行,這個在Android中是非常有用的,因為在Android中只能在UI線程中跟新UI,所以在onEvnetMainThread方法中是不能執行耗時操作的。
onEventBackground:如果使用onEventBackgrond作為訂閱函數,那麼如果事件是在UI線程中發布出來的,那麼onEventBackground就會在子線程中運行,如果事件本來就是子線程中發布出來的,那麼onEventBackground函數直接在該子線程中執行。
onEventAsync:使用這個函數作為訂閱函數,那麼無論事件在哪個線程發布,都會創建新的子線程在執行onEventAsync。
基本用法引入EventBus:
compile 'org.greenrobot:eventbus:3.0.0'
定義事件:
public class MessageEvent { /* Additional fields if needed */ }
註冊事件接收者:
eventBus.register(this);
發送事件:
eventBus.post(event)
接收消息並處理:
public void onEvent(MessageEvent event) {}
註銷事件接收:
eventBus.unregister(this);
最後,proguard 需要做一些額外處理:
#EventBus -keepclassmembers class ** { public void onEvent*(**); void onEvent*(**); }
實戰舉例
第一步:自定義一個定義Event事件,用來封裝信息
例子如下:
public class UserEvent { private String userName; public UserEvent() { } public UserEvent(String userName) { this.userName = userName; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; }}
第二步:註冊訂閱者和定義處理方法
public class MainActivity extends Activity { private Button btn, fragment_btn; private TextView service_tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //註冊訂閱者 EventBus.getDefault().register(this); btn = (Button) findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub Intent intent = new Intent(MainActivity.this, SecondActivity.class); startActivity(intent); } }); fragment_btn = (Button) findViewById(R.id.fragment_btn); fragment_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this, FragmenTestActivity.class); startActivity(intent); } }); service_tv = (TextView) findViewById(R.id.service_tv); startService(new Intent(this, EventTestService.class)); } //定義處理接收方法 @Subscribe public void onEventMainThread(UserEvent event) { btn.setText(event.getUserName()); service_tv.setText(event.getUserName()); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); }}
第三步:發送事件
public class SecondActivity extends Activity { private Button btn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); btn = (Button) findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final UserEvent ue = new UserEvent(); ue.setUserName("非著名程式設計師"); EventBus.getDefault().post(ue); finish(); } }); }}
fragment,service等之間的通信和activity之間的基本一樣,就不過多的貼代碼解釋了,感興趣的同學可以直接下載demo,裡面有它們之間的通信。
使用EventBus應該注意以下幾點:
同一個onEvent函數不能被註冊兩次,所以不能在一個類中註冊同時還在父類中註冊。
消息的接收是根據參數中的類名來決定執行哪一個接收處理方法的。即:訂閱者的處理方法是根據訂閱事件的類型來確定訂閱函數的。
每個事件可以有多個訂閱者。
當Post一個事件時,這個事件類的父類的事件也會被Post。
所有事件處理方法必需是public void類型的,並且只有一個參數表示EventType。
在這裡我把demo分享出去,demo裡包含了Activity之間的通信,fragment之間的通信和service與activity之間的通信。
下載地址:http://7xsgef.com1.z0.glb.clouddn.com/EventBusDemo2.zip