很早就知道这个库,这次不能放过他了要好好学习下。EventBus到底是什么呢?EventBus是一个小巧好用的事件总线框架。类似的事件总线框架还有otto。我的理解就是用来方便的在Activity,Fragment,Service等类之间方便的传递数据。EventBus可以实现Android Broadcast(广播)的功能,用Intent类传值的功能,startActivityForResult方法的功能。EventBus在我们的项目中还是值得使用,可以减少代码之间的耦合,使我们的代码更加简洁,方便做单元测试,效率也不用担心。下面介绍EventBus的使用。
EventBus github地址:
https://github.com/greenrobot/EventBus
EventBus官方地址
http://greenrobot.org/eventbus/
在App层的build.gradle文件中加入:compile ‘org.greenrobot:eventbus:3.0.0’
事件就是一个POJO (plain old Java object)。只有对属性的定义,没有其他东西。
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
最简单的订阅事件只需在类的方法上加上一个注解@Subscibe,当然这个注解可以设置参数
// This method will be called when a SomeOtherEvent is posted
@Subscribe
public void handleSomethingElse(SomeOtherEvent event) {
doSomethingWith(event);
}
当然订阅事件首先需要进行对事件订阅者进行注册。在开发中我们一般是在Activity或者Fragment中注册。注册需要结合生命周期进行。
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
我们可以在代码的任何地方发布事件,所有事件的订阅者,只要事件类型匹配,就能收到发布的时间。
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
只需三步我们就能用EventBus实现事件的订阅和发布,用EventBus来传递数据真是方便。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EventBus.getDefault().register(this);
// 实现startActivityForResult功能
findViewById(R.id.button).setOnClickListener(new
View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this,
SecondActivity.class));
}
});
}
@Subscribe
public void onMessage(MessageEvent event) {
Toast.makeText(this, event.getMessage(), Toast.LENGTH_SHORT).show();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageMainThread(MessageEvent event) {
Log.e("TAG", " message = " + event.getMessage());
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
我们在MainActivity 的onCreate方法中进行了注册,在onDestroy方法中解除了注册。onMessage方法和onMessageMainThread方法用来接收事件。我们的事件对象是MessageEvent。
public class MessageEvent {
private String message;
public MessageEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
这个是我们的事件对象类。
public class SecondActivity extends AppCompatActivity {
private Button button;
private EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
button = (Button) findViewById(R.id.button);
editText = (EditText) findViewById(R.id.edit_text);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().post(new MessageEvent(editText.getText().toString()));
SecondActivity.this.finish();
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
这个类的布局中有两个控件一个Button和一个EditText,点击按钮,把输入框中的字符转换成一个事件对象MessageEvent发送给事件的订阅者(在MainActiviy中)。这样在SecondActivity 类中的数据就被发送到MainActivity中去了。这个过程很像在MainActiviy通过startActivityForResult()方法跳转到SecondActivity中,然后在SecondActivity中获取数据,再通过MainActivity类的onActivityResult()方法获取来自SecondActivity 类的数据这一过程。上面的这个例子中的注解@Subscribe有一个参数threadMode且值是ThreadMode.MAIN。这个注解表示被注解的方法是运行在系统的主线程中的也就是UI线程,这样很方便我们对控件TextView、Button等的设置。
在上面的例子中我们提到一种线程模型ThreadMode.MAIN表示,被注解的方法是运行在主线程中的。下面分别介绍着四种线程模型:
ThreadMode.POSTING:事件在哪个线程发布出来的,onEvent就会在这个线程中运行,也就是说发布事件和接收事件线程在同一个线程。使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。这是默认方式。
ThreadMode.MAIN:不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行,接收事件就会在UI线程中运行,这个在Android中是非常有用的,因为在Android中只能在UI线程中跟新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。
我们知道在Android开发中有一个重要的组件广播,有一种广播叫粘性广播。普通的广播,我们先要注册广播,这样才能接收到发送过来的广播,如果是先发送后注册,那么发送过来的广播就接收不到。粘性广播,这种广播可以先发送后注册,就是说系统会保留之前发送的广播,后来的注册者也能接受到该广播。
发送粘性广播
EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));
接受粘性广播,参数sticky的值必须为true,默认为false
// UI updates must run on MainThread
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {
textField.setText(event.message);
}
EventBus会保留粘性广播,不用可以删除,先获取,后移除
MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {
// "Consume" the sticky event
EventBus.getDefault().removeStickyEvent(stickyEvent);
// Now do something with it
}
点击按钮,从两个EditText中获取数据,发送一个粘性事件,先发送
public class MakeUserInfoActivity extends AppCompatActivity {
private Button mButton;
private EditText mEditName;
private EditText mEditAge;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_make_user_info);
initWidgets();
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 下面两行代码,模拟Intent传递数据,一个User对象
User user = new User();
user.setName(mEditName.getText().toString());
user.setAge(mEditAge.getText().toString());
EventBus.getDefault().postSticky(user);
startActivity(new Intent(MakeUserInfoActivity.this,
ShowUserInfoActivity.class));
}
});
}
private void initWidgets() {
mEditName = (EditText) findViewById(R.id.et_name);
mEditAge = (EditText) findViewById(R.id.et_age);
mButton = (Button) findViewById(R.id.button);
}
}
注册事件,后注册,我们在onDestroy()方法中移除这个粘性事件
public class ShowUserInfoActivity extends AppCompatActivity {
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_user_info);
mTextView = (TextView) findViewById(R.id.tv_user_info);
// 注意要先初始化控件,防止onMessageEventMainThread方法执行的时候控件尚未初 始化,空指针异常
EventBus.getDefault().register(this);
}
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onMessageEventMainThread(User user) {
Log.e("TAG", "User.name = " + user.getName());
Log.e("TAG", "User.age = " + user.getAge());
mTextView.setText(user.getName() + "-" + user.getAge());
}
@Override
protected void onDestroy() {
super.onDestroy();
if (EventBus.getDefault().getStickyEvent(User.class) != null) {
EventBus.getDefault().removeStickyEvent(EventBus.getDefault().getStickyEvent(User.class));
}
EventBus.getDefault().unregister(this);
}
}
Android的广播有优先级的概念,EventBus事件总线框架也有这概念。
我在注解@Subscribe有个参数priority默认值是0,通过这个参数我们可以给订阅者加上优先级。数值越大,可以越优先获取传过来的事件。
@Subscribe(priority = 1);
public void onEvent(MessageEvent event) {
...
}
优先级高的可以,优先获取传来事件,之后还可以取消事件往优先级低的订阅者传递。在文章底部给出的两个代码中有关于优先级的例子。
// Called in the same thread (default)
@Subscribe
public void onEvent(MessageEvent event){
// Process the event
...
// Prevent delivery to other subscribers
EventBus.getDefault().cancelEventDelivery(event) ;
}
subscriber index(订阅者索引是)EventBus3.0的新特新,它可以有效的提高代码的执行效率。订阅者索引是通过EventBus 的annotation processor在编译期间产生的。我们知道EventBus事件总线框架用到了注解,注解信息一般是在软件运行期通过反射获取的,这一过程损失了效率。EventBus 的annotation processor在编译期间就处理了注解的信息,提高了效率。
对于Android Gradle Plugin version 2.2.0 或更高版本
android {
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = [ eventBusIndex 'com.example.myapp.MyEventBusIndex']
}
}
}
}
dependencies {
compile 'org.greenrobot:eventbus:3.0.0'
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.0.1'
}
com.example.myapp.MyEventBusIndex是在编译的时候产生的索引类。位置在
public class MyApllication extends Application {
@Override
public void onCreate() {
super.onCreate();
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
}
}
我们在项目的入口,用addIndex()方法增加编译器产生的索引类。通过installDefaultEventBus()方法,我们可以像原来的样子获取EventBus实例。
事件注册类
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EventBus.getDefault().register(this);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, PostIndexActivity.class));
}
});
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageMainThread(String str) {
Log.e("TAG", "time got event = " + System.currentTimeMillis());
Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
事件发送类
public class PostIndexActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_post_index);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("TAG", "time send event = " + System.currentTimeMillis());
EventBus.getDefault().post("hello world!");
PostIndexActivity.this.finish();
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
在上面的例子中我们打印了事件发送和接收的时间,发现时间差在1毫秒以内,就是说发送事件和接收事件打印出来的时间一样。笔者通过测试发现,在模拟器和真机上用不用索引类,时间差都在1毫秒内。真是效率不是问题。
当我们需要出正式版的时候,需要用ProGrard混淆代码和去掉不必要的代码。
-keepattributes *Annotation*
-keepclassmembers class ** {
@org.greenrobot.eventbus.Subscribe ;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
(java.lang.Throwable);
}
https://github.com/greenrobot/EventBus
http://greenrobot.org/eventbus/
http://blog.csdn.net/z609933542/article/details/50953166
http://android.jobbole.com/81098/
http://android.jobbole.com/82049/
http://android.jobbole.com/82050/
EventBusDemo01