Android EventBus 使用小结

文章目录
  1. 1. 简介 EventBus
  2. 2. 基本使用
  3. 3. 注意事项
  4. 4. 参考文献

人们眼中的天才,并非卓越非凡,而是付出了持续不断的努力,一万小时的锤炼是任何人从平凡变成超凡的必要条件。

EventBus 使用已经有段时间了,姑且做一个小结,让知识结构条理化。

简介 EventBus

EventBus 是一种针对 Android 优化的发布 / 订阅 (publish / subscribe) 事件总线。其主要特性:

  • 简化了组件之间的通信,解耦了事件发送者和接收者,在 Activity、Fragment 和后台线程之间运转良好,同时,避免了复杂的以及易错的依赖和生命周期问题;
  • 简化代码,速度快且开销很小;
  • 上亿级安装量的 App 证明其优越性,有着更高级的特点如传递线程和订阅优先级等。

示意图如下:

从示意图可以看出,由左到右,EventBus 有三个主要元素:

  • Publisher:发布者,用于通知 Subscriber 有事件发生。其特性即,能在任意线程和任意位置发送事件,调用 EventBus.post(Object o) 方法,使用默认的单例 EventBus.getDefault() 实例化 EventBus 对象。而后,由 post 方法参数的类型,自动调用并订阅相应类型事件的方法;
  • Event:事件,可以是任意类型的对象;
  • Subscriber:订阅者,接收特定的事件。EventBus 中,使用约定来指定事件订阅者,以简化使用。所有事件的订阅都是以 onEvent 开头的方法,与相应的线程模式相关。

关于线程模式,有以下四个:

  • POSTING,事件的处理和事件的发布处于相同的线程,事件的传递是同步完成的,所有的订阅者在发布完成后都会被调用。由于其避免了线程完全切换,这种线程模式意味着最小的开销。事件处理的时间不能太长,否则会影响事件的发步线程,该线程甚至或许是 UI 主线程。这是处理简单任务的推荐模式,不要求主线程时能很快完成。
  • MAIN,订阅者会在 Android 的 UI 主线程被调用。若 post 线程是主线程,事件处理程序方法将会被同步地直接调用,如 POSTING 一样。使用此模式的事件处理程序须快速返回相应结果,以避免阻塞主线程,引起 ANR。
  • BACKGROUND,订阅者将在后台线程中被调用。若 post 线程不是主线程,则在该 post 线程中直接调用事件处理程序方法;若 post 线程是主线程,EventBus 会使用一个单一的后台线程,其将有序地递送所有的事件。使用该模式的事件处理程序也应该快速返回相应结果,以避免阻塞后台线程。
  • ASYNC,事件处理程序方法将在单独的线程中被调用。这始终与 post 线程和主线程无关。post 事件也从来不用等待使用此模式的事件处理程序方法。若遇到诸如网络访问,其执行可能需要一些时间的话,事件处理程序方法应使用该模式。注意,应避免同时触发大量的长时间运行的异步处理程序方法,以限制并发线程的数量。EventBus 使用线程池从已完成的,异步的事件处理通知中有效地重用线程。

基本使用

I. gradle 中引入依赖:

1
compile 'org.greenrobot:eventbus:3.0.0'

II. 接着,定义事件:

1
2
3
public static class MessageEvent { 
/* Additional fields if needed */
}

III. 准备订阅者:声明并在订阅方法上加上注解,有选择性地指定一个线程模式:

1
2
3
4
@Subscribe(threadMode = ThreadMode.Main)
public void onMessageEvent(MessageEvent event) {
/* Do something */
}

IV. 注册和注销订阅者。比如,Android 中,Activities 和 Fragments 之间应该由其生命周期来进行注册和注销:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}

//...

@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}

V. Post 事件:

1
EventBus.getDefault().post(new MessageEvent());

说了这么多,接下来看一个 EventBusDemo,里面综合了 Service 与 Activity 之间的通信、 Activity 之间的通信、Fragment 之间的通信和 Fragment 与 Activity 之间的通信。

首先,引入依赖后,自定义一个 MessageEvent 事件,以封装相关信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MessageEvent {

private String mMessage;

public MessageEvent() {

}

public MessageEvent(String message) {
mMessage = message;
}

public String getMessage() {
return mMessage;
}

public void setMessage(String message) {
mMessage = message;
}

}

接着,声明订阅者和定义相关的处理方法,MainActivity 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private TextView mTvService;
private Button mBtnActivity, mBtnFragment;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

EventBus.getDefault().register(this);

mBtnActivity = (Button) findViewById(R.id.btn_activity);
mBtnFragment = (Button) findViewById(R.id.btn_fragment);
mTvService = (TextView) findViewById(R.id.tv_service);
startService(new Intent(this, EventService.class));

mBtnActivity.setOnClickListener(this);
mBtnFragment.setOnClickListener(this);
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_activity:
startActivity(new Intent(this, SecondActivity.class));
break;
case R.id.btn_fragment:
startActivity(new Intent(this, FragmentContainerActivity.class));
break;
default:
break;
}
}

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
mBtnActivity.setText(event.getMessage());
mTvService.setText(event.getMessage());
}

@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}

}

代码很简练,onCreate() 方法里调用到了 startService() 方法,EventService 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class EventService extends Service {

public EventService() {

}

@Override
public IBinder onBind(Intent intent) {
return new Binder();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new MyThread().start();
return super.onStartCommand(intent, flags, startId);
}

class MyThread extends Thread {

@Override
public void run() {
EventBus.getDefault().post(new MessageEvent("Service 与 Activity 通信成功!"));
}
}

}

打开 App,出现以下 UI,则 Service 与 Activity 之间通信成功。

点击第一个按钮,跳到 SecondActivity:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class SecondActivity extends AppCompatActivity implements View.OnClickListener {

private Button mBtnSecond;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);

mBtnSecond = (Button) findViewById(R.id.btn_back);
mBtnSecond.setOnClickListener(this);
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_back:
EventBus.getDefault().post(new MessageEvent("Activity 之间通信成功!"));
finish();
break;
default:
break;
}
}

}

代码也很简练,UI 如下:

点击按钮,返回 MainActivity,出现 UI:

那么,Activity 之间的通信便成功了。主界面中,点击第二个按钮,出现 UI:

其中,FragmentOne 的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class FragmentOne extends Fragment implements View.OnClickListener {

private Button mBtnOne;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_one, container, false);
mBtnOne = (Button) view.findViewById(R.id.btn_left);
mBtnOne.setOnClickListener(this);
return view;
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_left:
EventBus.getDefault().post(new MessageEvent("Fragment 之间通信成功!"));
break;
default:
break;
}
}

}

此外,FragmentTwo 的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class FragmentTwo extends Fragment {

private TextView mTvText;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EventBus.getDefault().register(this);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_two, container, false);
mTvText = (TextView) view.findViewById(R.id.tv_right);
return view;
}

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
mTvText.setText(event.getMessage());
}

@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}

}

点击“与右边的 Fragment 通信”按钮,右边的文字改变:

则 Fragment 之间通信成功。最后,点击返回键,回到主界面,UI 变为:

FragmentOne 发出的消息,MainActivity 也收到了,则 Fragment 与 Activity 之间的通信成功了。

注意事项

EventBus 的使用大体如上,下面来看几点注意事项:

1.一个事件可以有多个订阅者;

2.Post 一个事件时,同时,该事件类的父类事件也会 Post 出来;

3.同一个 onEvent() 方法不能被注册两次,故不能在一个类中注册,同时还在其父类中注册;

4.事件处理方法须是 Public Void 类型的,只有一个参数指的是 EventType;

5.其实,EventBus 是内部用 Map 存储,Post 消息的时候,照实参从 Map 里寻找方法,再反射调用的。

至此,关于 Android EventBus 的使用小结到此结束,下一篇打算翻看源码,以深入理解 EventBus。

本人才疏学浅,如有疏漏错误之处,望读者中有识之士不吝赐教,谢谢。

1
Email: [email protected] / WeChat: Wolverine623

您也可以关注我个人的微信公众号码农六哥第一时间获得博客的更新通知,或后台留言与我交流

参考文献

1.https://github.com/greenrobot/EventBus

2.http://www.cnblogs.com/angeldevil/p/3715934.html

3.http://blog.csdn.net/lmj623565791/article/details/40794879