EventBus是一款针对优化的发布/订阅事件总线。简化了应用程序内各组件间、组件与后台线程间的通信。优点是开销小,代码更优雅,以及将发送者和接收者解耦。
使用场景:
假如有两个页面A和B,A页面变化后要让B页面也发生变化,怎么办?可以发广播,但是比较重量级,因此我们的主角登场了
使用步骤:
(1)添加依赖:
在app的build.gradle里面
dependencies {
...
compile 'org.greenrobot:eventbus:3.0.0'
}
(2)在订阅事件所属的Activity或者fragment里面注册,一般写在onCreate()方法里
EventBus.getDefault().register(this);
注意:在页面销毁的时候要注销EventBus,一般在onDestory()方法里
EventBus.getDefault().unregister(this);
(3)在事件产生的地方(可能不好理解,看例子就行)调用
EventBus.getDefault().post(new Object());
(4)在事件订阅的地方调用
@Subscribe(threadMode = ThreadMode.MAIN)
public void updateUI(){
//在这里处理相应的逻辑
}
下面先看个例子再细说
A页面展示用户信息,点击按钮进入B页面,在B页面编辑用户信息,编辑完成后点击按钮退出B按钮退出B页面,同时A页面的信息是最新的
先看下效果:



先看下A页面实现:
public class Activity_A extends AppCompatActivity {
private TextView tv_name;
private TextView tv_age;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EventBus.getDefault().register(this);
tv_name = (TextView) findViewById(R.id.tv_name);
tv_age = (TextView) findViewById(R.id.tv_age);
button = (Button) findViewById(R.id.bt_edit);
//进入编辑页面,要把这个页面的信息通过intent传递过去
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Activity_A.this,Activity_B.class);
intent.putExtra("name",tv_name.getText().toString().trim());
intent.putExtra("age",tv_age.getText().toString().trim());
startActivity(intent);
}
});
}
//B页面编辑完信息,使用EventBus发布信息,该方法会接受信息并更新用户信息
//EventBus3.0之后使用注解的方式,这样方法的名字可以任意写,比如这里的updateUserInfo(这个参数和B页面post方法的参数类型一定一样)
@Subscribe(threadMode = ThreadMode.MAIN)
public void updateUserInfo(Person person){
tv_name.setText(person.getName());
tv_age.setText(person.getAge());
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
public class Activity_B extends AppCompatActivity {
private EditText et_name;
private EditText et_age;
private Button bt_finish;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
//注意:该页面只是发出消息,并没有接受消息,所以不需要也不能有EventBus.getDefault().register(this);
et_name = (EditText) findViewById(R.id.et_name);
et_age = (EditText) findViewById(R.id.et_age);
bt_finish = (Button) findViewById(R.id.bt_finish);
//获取A页面传递过来的值,并初始化页面
Intent intent = getIntent();
et_name.setText(intent.getStringExtra("name"));
et_age.setText(intent.getStringExtra("age"));
//点击完成按钮,关闭该页面回到A页面
bt_finish.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Person person = new Person();
person.setAge(et_age.getText().toString().trim());
person.setName(et_name.getText().toString().trim());
//这个person对象就会传到A页面updateUserInfo(Person person)中的参数person里面
EventBus.getDefault().post(person);
Activity_B.this.finish();
}
});
}
}
//一个javabean
class Person{
private String age;
private String name;
public Person() {
}
public Person(String age, String name) {
this.age = age;
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
布局很简单,就不贴了
几个细节说一下:
(1)除了一般的post方法,我们还会使用
EventBus.getDefault().postSticky(object);
所谓粘性事件,比如上面的例子,当我在B页面编辑完信息回到A之后不想马上更新用户信息,而是希望点击一个按钮之后再更新,

修改A的代码:
不同之处已经添加注释,用!!!包裹
public class Activity_A extends AppCompatActivity {
private TextView tv_name;
private TextView tv_age;
private Button button;
private Button bt_update;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//!!!一开始不会注册!!!
// EventBus.getDefault().register(this);
tv_name = (TextView) findViewById(R.id.tv_name);
tv_age = (TextView) findViewById(R.id.tv_age);
button = (Button) findViewById(R.id.bt_edit);
bt_update = (Button) findViewById(R.id.bt_update);
//!!!点击更新按钮之后才注册!!!
bt_update.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().register(Activity_A.this);
}
});
//进入编辑页面,要把这个页面的信息通过intent传递过去
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Activity_A.this,Activity_B.class);
intent.putExtra("name",tv_name.getText().toString().trim());
intent.putExtra("age",tv_age.getText().toString().trim());
startActivity(intent);
}
});
}
//B页面编辑完信息,使用EventBus发布信息,该方法会接受信息并更新用户信息
//EventBus3.0之后使用注解的方式,这样方法的名字可以任意写,比如这里的updateUserInfo(这个参数和B页面post方法的参数类型一定一样)
//!!!这里多了一个sticky = true,说明接收一个粘性事件!!!
@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
public void updateUserInfo(Person person){
tv_name.setText(person.getName());
tv_age.setText(person.getAge());
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
B页面只改动一个地方:
EventBus.getDefault().postSticky(person);
(2)订阅事件的优先级
我们在A页面写两个方法接受订阅事件,看谁先执行,注意我们加了priority这个属性
@Subscribe(threadMode = ThreadMode.MAIN,priority = 100)
public void updateUserInfo(Person person){
System.out.println("updateUserInfo");
tv_name.setText(person.getName());
tv_age.setText(person.getAge());
}
@Subscribe(threadMode = ThreadMode.MAIN,priority = 10000)
public void updateUserInfo2(Person person){
System.out.println("updateUserInfo2");
tv_name.setText(person.getName());
tv_age.setText(person.getAge());
}
结果:
priority值大的方法先执行
13:50:45.745 15870-15870/com.dgtech.sss.eventbusdemo I/System.out: updateUserInfo2
13:50:45.746 15870-15870/com.dgtech.sss.eventbusdemo I/System.out: updateUserInfo
priority值越大,优先级越高,默认值是0
(3)四种threadMode
①ThreadMode.MAIN
无论在哪个线程post(),订阅方法都在主线程执行
A修改:
@Subscribe(threadMode = ThreadMode.MAIN)
public void updateUserInfo(Person person){
System.out.println("订阅方法执行的线程是:"+Thread.currentThread().getName());
tv_name.setText(person.getName());
tv_age.setText(person.getAge());
}
B修改:
EventBus.getDefault().post(person);
System.out.println("post线程是: "+Thread.currentThread().getName());
结果:
14:00:07.239 23105-23105/com.dgtech.sss.eventbusdemo I/System.out: 订阅方法执行的线程是:main
14:00:07.239 23105-23105/com.dgtech.sss.eventbusdemo I/System.out: post线程是: main
②ThreadMode.POSTING
在哪个线程post就在哪个线程执行订阅方法
A修改:
@Subscribe(threadMode = ThreadMode.POSTING)
public void updateUserInfo(Person person){
System.out.println("订阅方法执行的线程是:"+Thread.currentThread().getName());
tv_name.setText(person.getName());
tv_age.setText(person.getAge());
}
B修改:
new Thread(){
@Override
public void run() {
EventBus.getDefault().post(person);
System.out.println("post线程是: "+Thread.currentThread().getName());
}
}.start();
结果:
14:03:55.650 26605-26800/com.dgtech.sss.eventbusdemo I/System.out: 订阅方法执行的线程是:Thread-2
14:03:55.652 26605-26800/com.dgtech.sss.eventbusdemo I/System.out: post线程是: Thread-2
③ThreadMode.BACKGROUND
如果post实在主线程,则订阅方法会新创建一个子线程并在该子线程执行;如果post在子线程,那么订阅方法就在该子线程执行
还是上面②的代码
执行结果:
14:09:09.293 31005-31176/com.dgtech.sss.eventbusdemo I/System.out: 订阅方法执行的线程是:Thread-2
14:09:09.296 31005-31176/com.dgtech.sss.eventbusdemo I/System.out: post线程是: Thread-2
修改上面的代码,把post方法放到主线程:
EventBus.getDefault().post(person);
System.out.println("post线程是: "+Thread.currentThread().getName());
结果:
14:10:47.001 544-544/com.dgtech.sss.eventbusdemo I/System.out: post线程是: main
14:10:47.002 544-1078/com.dgtech.sss.eventbusdemo I/System.out: 订阅方法执行的线程是:pool-1-thread-1
④ThreadMode.ASYNC
无论post在哪个线程执行,订阅方法都新创建线程来执行
还是③的代码
执行结果:
14:13:19.439 4641-4891/com.dgtech.sss.eventbusdemo I/System.out: post线程是: Thread-2
14:13:19.439 4641-4892/com.dgtech.sss.eventbusdemo I/System.out: 订阅方法执行的线程是:pool-1-thread-1
以上大概就是项目中会涉及到EventBus的使用了,后面我们会分析EventBus的原理
网友评论