人们眼中的天才,并非卓越非凡,而是付出了持续不断的努力,一万小时的锤炼是任何人从平凡变成超凡的必要条件。
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 { }
III. 准备订阅者:声明并在订阅方法上加上注解,有选择性地指定一个线程模式:
1 2 3 4 @Subscribe (threadMode = ThreadMode.Main)public void onMessageEvent (MessageEvent event) { }
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.https://github.com/greenrobot/EventBus
2.http://www.cnblogs.com/angeldevil/p/3715934.html
3.http://blog.csdn.net/lmj623565791/article/details/40794879