1. EventBus序言
EventBus是一款针对Android优化的发布/订阅事件总线。主要功能是替代Intent、Handler、BroadCast在Fragment、Activity、Service、线程之间传递消息.优点是开销小,代码更优雅。以及将发送者和接收者解耦。EventBus在GitHub上的开源库地址,刚开始使用的可以看一下,GitHub上有最基本的使用方法。
EventBus优点:
- 简化组件间的通信
(1).对发送和接受事件解耦
(2).可以在Activity,Fragment,和后台线程间执行
(3).避免了复杂的和容易出错的依赖和生命周期问题 - 让你的代码更简洁
- 更快
- 更轻量(jar包小于50K)
- 拥有先进的功能比如线程分发,用户优先级等等
关于EventBus的使用主要遵循以下三步骤:
-
自定义一个事件(事件是没有任何特殊要求的PLJO(Plain Old Java Object))
public class MessageEvent { /* Additional fields if needed */ }
-
准备订阅(订阅者)
订阅者实现了事件处理方法(订阅者方法),这些方法将在事件发布时调用。Subscribe方法使用@subscribe 注解定义,对于EventBus 3,方法名可以自有选择// This method will be called when a MessageEvent is posted (in the UI thread for Toast) @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) { Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show(); } // This method will be called when a SomeOtherEvent is posted @Subscribe public void handleSomethingElse(SomeOtherEvent event) { doSomethingWith(event); }
Subscriber需要从“总线”来“注册”和“解注册”。Subscriber 只有在注册后才可以接收到事件。对于 Android ,在 Activity 和 Fragment 中通常应该根据生命周期注册。对于大多数情况,分别在
onStart
和onStop
注册和解注册就可以@Override public void onStart() { super.onStart(); EventBus.getDefault().register(this); } @Override public void onStop() { EventBus.getDefault().unregister(this); super.onStop(); }
-
发布事件
代码中的任意部分都可以发布事件。所有已注册并且匹配该类型的 Subscriber(订阅者)都会收到该事件:EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
2 EventBus基本使用
EventBus最基本的引用如下:
implementation 'org.greenrobot:eventbus:3.1.1'
添加这个引用之后就可以使用EventBus了
简单使用示例:
-
简单框架搭建:创建两个Activity页面,设置Activity跳转
-
新建一个类,FirstEvent
public class FirstEvent { private String mMsg; public FirstEvent(String msg) { mMsg = msg; } public String getmMsg() { return mMsg; } }
这个类很简单,构造时传进去一个字符串,然后可以通过getMsg()获取出来
-
在要接收消息的页面注册EventBus
我们要在MainActivity中接收发过来的消息,所以在MainActivity中注册消息。在onCreate()函数中注册EventBus,在onDestroy()函数中反注册public class MainActivity extends AppCompatActivity { private Button mButton; private TextView mTv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 注册EventBus EventBus.getDefault().register(this); mButton = (Button) findViewById(R.id.btn_try); mTv = (TextView) findViewById(R.id.tv); mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(getApplicationContext(), SecondActivity.class); startActivity(intent); } }); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); } }
-
发送消息,使用EventBus的Post方法来实现,发送过去即新建的类的实例。
public class SecondActivity extends AppCompatActivity { private Button mBtnFirstEvent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); mBtnFirstEvent = (Button) findViewById(R.id.btn_first_event); mBtnFirstEvent.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EventBus.getDefault().post(new FirstEvent("FirstEvent btn Clicked")); } }); } }
-
接收消息
接收消息,这里使用EventBus中常用的onEventMainThread()
函数来接收消息。但是注意必须是要声明@Subscribe
在MainActivity中重写onEventMainThread(FirstEvent event),参数就是我们自己定义的类,收到实例后,将其携带的消息取出,一方面Toast出去,一方面传到TextView中:
@Subscribe
public void onEventMainThread(FirstEvent event) {
String msg = "onEventMainThread收到消息:" + event.getmMsg();
Log.d("MainActivity", msg);
mTv.setText(msg);
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
3. EventBus其他函数使用
前面简单演示了onEventMainThread()
函数的接收,除此之外,还有:
- onEvent
- onEventMainThread
- onEventBackgroundThead
- onEventAsync
告知观察者事件发生时通过EventBus.post函数实现,这个过程叫做事件的发布,观察者被告知事件发生叫做事件的接收,是通过下面的订阅函数实现的
onEvent
:使用onEvent作为订阅函数,那么该事件在哪个线程发布出来的,onEvent就会在这个线程中运行,也就是说发布事件和接收事件线程在同一个线程。使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。
onEventMainThread
:如果使用onEventMainThread作为订阅函数,那么不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行,接收事件就会在UI线程中运行,这个在Android中是非常有用的,因为在Android中只能在UI线程中跟新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。
onEventBackground
:如果使用onEventBackgrond作为订阅函数,那么如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行,如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行。
onEventAsync
:使用这个函数作为订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync。
当发过来一个消息时,EventBus怎么知道要调哪个函数,就看哪个函数传进去的参数是这个类的实例,就调哪个。
3.1 订阅事件处理进阶
在EventBus3.0之后,可以自定义订阅事件处理方法名,可以在@Subscribe之后定义处理函数
@Subscribe(threadMode = ThreadMode.MAIN, priority = 2, sticky = true)
public void eventMessageHander(FirstEvent event) {
String msg = "eventMessageHandle收到消息:" + event.getmMsg();
Log.d(TAG, msg);
}
备注:threadMode指线程模式,priority指事件的优先级,sticky是否是粘性事件
threadMode
线程模式有五种:MAIN
UI主线程、BACKGROUND
后台线程、POSTING
和发布者处在同一个线程、ASYNC
异步线程 、MAIN_ORDERED
,UI主线程,但不会直接调用处理消息的方法,而是把事件加入到主线程的消息循环队列中执行。不写注解默认为POSTING模式priority
:和Boardcast接收者的优先级差不多,数越大优先级越高,一般0-100;sticky
:注册期间,所有粘性订户将立即获得之前发布的粘性事件。
3.2 普通事件与粘性事件
EventBus.getDefault().postSticky(new MessageEvent("发送粘性事件"));
普通事件的发送如上,其中EventBus是为了给已经存在的窗体传递信息,而且订阅者必须要注册且不能被注销了,否者接收不到消息。
粘性事件的发送如下:
EventBus.getDefault().postSticky(new MessageEvent("发送粘性事件"));
粘性事件发送后只要不取消就会一直存在。
粘性事件简单来说,就是发送事件之后再订阅该事件也能收到该事件。Android中也有这样的实例,就是Sticky Broadcast,即粘性广播。
EventBus也提供了这样的功能,不同的是EventBus会存储所有的Sticky事件,如果某个事件不再需要存储则需要手动进行移除。
3.3 移除事件
- 普通事件删除
EventBus.getDefault().cancelEventDelivery(event);
备注:事件取消仅限于ThreadMode.PostThread
下才可以使用
-
粘性事件删除
最近发布的粘性事件在其新订阅者注册后将会自动传递给新订阅者。但有时可能更方便手动检查粘性事件。有时我们也需要移除粘性事件,以免它在传递下去。
//指定粘性事件删除
T stickyEvent = EventBus.getDefault().getStickyEvent(eventType);
if (stickyEvent != null) {
EventBus.getDefault().removeStickyEvent(stickyEvent);
}
//删除所有粘性事件
EventBus.getDefault().removeAllStickyEvents();
3.4 ProGuard
ProGuard 会混淆方法名甚至移除没有被调用的方法(dead code removal). 由于 Subscriber 方法一般情况下并不会被直接调用, 所以 ProGuard 假定它们是”无用的”. 因此当打开 ProGuard 的最小化开关之后, 必须明确指定保留这些 Subscriber 方法.
在ProGuard配置文件添加下列规则:
-keepattributes *Annotation*
-keepclassmembers class ** {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
<init>(java.lang.Throwable);
}