你還在為刷新ui傷透腦筋嗎?你還在琢磨如何使用接口回調或者handle來實現嗎?如果你想到了使用觀察者模式,那麼一個很屌的Android開源框架EventBus:主要功能是替代Intent、Handler、BroadCast在Fragment、Activity、Service、線程之間傳遞消息。他的最牛逼優點是開銷小,代碼簡潔,解耦代碼。
如果你沒有使用過eventBus那麼很遺憾你錯過了很多,不過沒有關系3.0的正式發布,使用沒有什麼大不一樣只是性能更好。個人建議直接使用3.0.0的版本,也不要去使用2.4和3.0beta1的版本了。
看圖說話:
EventBus是一款針對Android優化的發布/訂閱(publish/subscribe)事件總線。
EventBus作為一個消息總線,有三個主要的元素:
Event:事件。可以是任意類型的對象 Subscriber:事件訂閱者,接收特定的事件。在EventBus中,使用約定來指定事件訂閱者以簡化使用。即所有事件訂閱都都是以onEvent開頭的函數,具體來說,函數的名字是onEvent,onEventMainThread,onEventBackgroundThread,onEventAsync這四個,這個和
ThreadMode(下面講)有關。 Publisher:事件發布者,用於通知 Subscriber 有事件發生。可以在任意線程任意位置發送事件,直接調用eventBus.post(Object) 方法,可以自己實例化 EventBus
對象,但一般使用默認的單例就好了:EventBus.getDefault(), 根據post函數參數的類型,會自動調用訂閱相應類型事件的函數。
引入eventbus:2.4.0(回顧老版本)
compile ‘de.greenrobot:eventbus:2.4.0’
引入eventbus:3.0.0-beta1
compile ‘de.greenrobot:eventbus:3.0.0-beta1’
引入eventbus:3.0.0
compile ‘org.greenrobot:eventbus:3.0.0’
public class MessageEvent {
......
}
EventBus.getDefault().register(this);
EventBus.getDefault().post(messageEvent);
在3.0之前,EventBus還沒有使用注解方式。消息處理的方法也只能限定於onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,分別代表四種線程模型。而在3.0之後,消息處理的方法可以隨便取名,但是需要添加一個注解@Subscribe,並且要指定線程模型(beta1默認為PostThread,正式版默認為POSTING),四種線程模型,下面會講到。
注意,事件處理函數的訪問權限必須為public,否則會報異常。
public void onEvent(MessageEvent event) {
// 事件在哪個線程發布出來的,onEvent就會在這個線程中運行,也就是說發布事件和接收事件線程在同一個線程。使用這個方法時,在onEvent方法中不能執行耗時操作,如果執行耗時操作容易導致事件分發延遲。
}
public void onEventMainThread(MessageEvent event) {
// 不論事件是在哪個線程中發布出來的,onEventMainThread都會在UI線程中執行,接收事件就會在UI線程中運行,這個在Android中是非常有用的,因為在Android中只能在UI線程中跟新UI,所以在onEvnetMainThread方法中是不能執行耗時操作的。
}
public void onEventBackgroundThread(MessageEvent event){
//那麼如果事件是在UI線程中發布出來的,那麼onEventBackground就會在子線程中運行,如果事件本來就是子線程中發布出來的,那麼onEventBackground函數直接在該子線程中執行。
}
public void onEventAsync(MessageEvent event){
//使用這個函數作為訂閱函數,那麼無論事件在哪個線程發布,都會創建新的子線程在執行onEventAsync.
}
在EventBus 3.0.0的使用是這樣的
@Subscribe(threadMode = ThreadMode.PostThread) //3.0.0-beta1
public void onMessageEventPost(UserEvent event) {
//默認方式, 在發送線程執行
}
@Subscribe(threadMode = ThreadMode.MainThread)
public void onMessageEventMain(UserEvent event) {
//在ui線程執行
}
@Subscribe(threadMode = ThreadMode.BackgroundThread)
public void onMessageEventBackground(UserEvent event) {
//在後台線程執行
}
@Subscribe(threadMode = ThreadMode.Async)
public void onMessageEventAsync(UserEvent event) {
//強制在後台執行
}
(2) 正式版的寫法
@Subscribe(threadMode = ThreadMode.POSTING) //3.0.0
public void onMessageEventPost(UserEvent event) {
//默認方式, 在發送線程執行
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEventMain(UserEvent event) {
//在ui線程執行
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessageEventBackground(UserEvent event) {
//在後台線程執行
}
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessageEventAsync(UserEvent event) {
//強制在後台執行
}
EventBus.getDefault().unregister(this);
#EventBus
-keepclassmembers class ** {
public void onEvent*(**);
void onEvent*(**);
}
看下簡單實現的效果:
看下具體的代碼使用:
package com.losileeya.eventbusapp;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.losileeya.eventbusapp.event.EventBusEvents;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn_first,btn_second,btn_third;
private TextView tv_toast;
private TextView tv_default,tv_main,tv_background,tv_asy;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EventBus.getDefault().register(this);
btn_first = (Button) findViewById(R.id.btn_first);
btn_second = (Button) findViewById(R.id.btn_second);
btn_third = (Button) findViewById(R.id.btn_third);
tv_toast= (TextView) findViewById(R.id.tv_toast);
tv_default= (TextView) findViewById(R.id.tv_default);
tv_main= (TextView) findViewById(R.id.tv_main);
tv_background= (TextView) findViewById(R.id.tv_background);
tv_asy= (TextView) findViewById(R.id.tv_asy);
btn_first.setOnClickListener(this);
btn_second.setOnClickListener(this);
btn_third.setOnClickListener(this);
}
@Override
public void onClick(View v) {
Intent intent;
switch (v.getId()){
case R.id.btn_first:
intent = new Intent(MainActivity.this,FirstActivity.class);
startActivity(intent);
break;
case R.id.btn_second:
intent = new Intent(MainActivity.this,SecondActivity.class);
startActivity(intent);
break;
case R.id.btn_third:
intent = new Intent(MainActivity.this,ThirdActivity.class);
startActivity(intent);
break;
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageMain(EventBusEvents.FirstEvent firstEvent){
tv_toast.setText(firstEvent.getValue());
Toast.makeText(this, firstEvent.getValue(),Toast.LENGTH_SHORT).show();
Log.d("zy", "onEventMainThread-->"+Thread.currentThread().getId());
tv_main.setText(Thread.currentThread().getId()+"");
}
/**
* 使用onEvent來接收事件,那麼接收事件和分發事件在一個線程中執行
* @param event
*/
@Subscribe(threadMode = ThreadMode.POSTING)
public void onPost(EventBusEvents.FirstEvent firstEvent)
{
Log.d("zy", "onEventPost-->"+Thread.currentThread().getId());
tv_default.setText(Thread.currentThread().getId()+"");
}
/**
* 使用onEventBackgroundThread來接收事件,如果分發事件在子線程運行,那麼接收事件直接在同樣線程
* 運行,如果分發事件在UI線程,那麼會啟動一個子線程運行接收事件
* @param event
*/
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onBackgroundThread(EventBusEvents.FirstEvent firstEvent)
{
Log.d("zy", "onEventBackgroundThread-->"+Thread.currentThread().getId());
tv_background.setText(Thread.currentThread().getId()+"");
}
/**
* 使用onEventAsync接收事件,無論分發事件在(UI或者子線程)哪個線程執行,接收都會在另外一個子線程執行
* @param event
*/
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onAsync(EventBusEvents.FirstEvent firstEvent)
{
Log.d("zy", "onEventAsync-->"+Thread.currentThread().getId());
tv_asy.setText(Thread.currentThread().getId()+"");
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
package com.losileeya.eventbusapp;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import com.losileeya.eventbusapp.event.EventBusEvents;
import org.greenrobot.eventbus.EventBus;
public class FirstActivity extends AppCompatActivity {
private Button btn_showDownLoad;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
btn_showDownLoad = (Button) findViewById(R.id.btn_toast);
btn_showDownLoad.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
EventBus.getDefault().post(new EventBusEvents.FirstEvent("我是從網絡下載的文本"));
}
}).start();
}
});
}
}
可以看出哪裡需要發送消息,那麼就必須使用:
EventBus.getDefault().post(your event)
然後你只需要訂閱就好了:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageMain(EventBusEvents.FirstEvent firstEvent){
tv_toast.setText(firstEvent.getValue());
Toast.makeText(this, firstEvent.getValue(),Toast.LENGTH_SHORT).show();
}