目录
1. EventBus 框架
EventBus,顾名思义即事件总线,是针对Android跨进程、线程通信的优化方案,在一定程度上可以代替Handle、Intent、Brodcast等实现通信;如下图所示即EventBus的运行框架。
在EventBus中主要有以下三个成员:
- Event:事件,可以自定义为任意对象,类似Message类的作用;
- Publisher:事件发布者,可以在任意线程、任意位置发布Event,已发布的Evnet则由EventBus进行分发;
- Subscriber:事件订阅者,接收并处理事件,需要通过register(this)进行注册,而在类销毁时要使用unregister(this)方法解注册。每个Subscriber可以定义一个或多个事件处理方法,其方法名可以自定义,但需要添加@Subscribe的注解,并指明ThreadMode(不写默认为Posting)。
1.1 五种ThreadMode
- Posting:直接在事件发布者所在线程执行事件处理方法;
- Main:直接在主线程中执行事件处理方法(即UI线程),如果发布事件的线程也是主线程,那么事件处理方法会直接被调用,并且未避免ANR,该方法应避免进行耗时操作;
- MainOrdered:也是直接在主线程中执行事件处理方法,但与Main方式不同的是,不论发布者所在线程是不是主线程,发布的事件都会进入队列按事件串行顺序依次执行;
- BACKGROUND:事件处理方法将在后台线程中被调用。如果发布事件的线程不是主线程,那么事件处理方法将直接在该线程中被调用。如果发布事件的线程是主线程,那么将使用一个单独的后台线程,该线程将按顺序发送所有的事件。
- Async:不管发布者的线程是不是主线程,都会开启一个新的线程来执行事件处理方法。如果事件处理方法的执行需要一些时间,例如网络访问,那么就应该使用该模式。为避免触发大量的长时间运行的事件处理方法,EventBus使用了一个线程池来有效地重用已经完成调用订阅者方法的线程以限制并发线程的数量。
后面会通过代码展示五种ThreadMode的工作方式。
2. EventBus的使用流程
1. build.gradle 中添加EventBus的依赖:
dependencies {
...
compile 'org.greenrobot:eventbus:3.1.1'
}
2. 定义Event事件类:
public class myEvent {
private String mMessage;
...
}
3. 添加订阅事件:
EventBus.getDefault().register(this);
4. 定义事件处理方法并添加注解,参数为定义的事件类:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(myEvent me){
...
}
5. 发布事件以触发事件处理方法:
EventBus.getDefault().post(new myEvent("this is first message !"));
3. EventBus应用
以下Demo以5中不同的ThreadMode定义了5个事件处理方法,并新开启一个线程作为事件发布者。
3.1 定义Event时间类
/**
* Created by wise on 2018/5/16.
*/
/**Event事件类**/
public class myEvent {
private String mMessage;
public myEvent(String message){
this.mMessage = message;
}
public void setMessage(String message){
this.mMessage = message;
}
public String getmessage(){
return this.mMessage;
}
}
3.2 EventBus功能实现
public class EventBusActivity extends AppCompatActivity {
private static final String TAG = "EventBusActivity";
private TextView tv_Event;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event_bus);
/**注册事件**/
EventBus.getDefault().register(this);
Thread thread1 = new Thread(new myThread1());
thread1.start();
}
/**事件处理方法**/
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMain(myEvent me){
Log.d(TAG,me.getmessage() + " onEventMain" + " thread:" + android.os.Process.myTid());
}
/**事件处理方法**/
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onEventMainOrdered(myEvent me){
Log.d(TAG,me.getmessage() + " onEventMainOrdered" + " thread:" + android.os.Process.myTid());
}
/**事件处理方法**/
@Subscribe(threadMode = ThreadMode.POSTING)
public void onEventPosting(myEvent te){
Log.d(TAG,te.getmessage() + " onEventPosting" + " thread:" + android.os.Process.myTid());
}
/**事件处理方法**/
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onEventBackground(myEvent me){
Log.d(TAG,me.getmessage() + " onEventBackground" + " thread:" + android.os.Process.myTid());
}
/**事件处理方法**/
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onEventAsync(myEvent me){
Log.d(TAG,me.getmessage() + " onEventAsync" + " thread:" + android.os.Process.myTid());
}
@Override
protected void onDestroy() {
super.onDestroy();
/**解注册**/
EventBus.getDefault().unregister(this);
}
public class myThread1 implements Runnable {
@Override
public void run() {
Log.d(TAG,"" + android.os.Process.myTid());
try {
Thread.sleep(1000);
/**事件发布**/
EventBus.getDefault().post(new myEvent("this is first message !"));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
执行结果如下:
05-24 17:17:47.335 24447 24478 D EventBusActivity: 24478
05-24 17:17:48.341 24447 24478 D EventBusActivity: this is first message ! onEventBackground thread:24478
05-24 17:17:48.341 24447 24498 D EventBusActivity: this is first message ! onEventAsync thread:24498
05-24 17:17:48.342 24447 24447 D EventBusActivity: this is first message ! onEventMain thread:24447
05-24 17:17:48.342 24447 24447 D EventBusActivity: this is first message ! onEventMainOrdered thread:24447
05-24 17:17:48.344 24447 24478 D EventBusActivity: this is first message ! onEventPosting thread:24478
主线程Tid为24447,子线程Tid为24478,可以看到每种ThreadMode的运行方式。另外我们可以通过定义不同的事件类作为post的参数来执行不同的事件执行方法,后一篇会分析源码解释调用事件处理方法的逻辑。
4. EventBus的粘性事件
以上的Demo中,事件订阅者的注册必须在发布事件之前,否则发布之后,订阅者无法接受到事件,而粘性事件则避免了这一问题,粘性事件的发布使用postSticky()方法即可,并在注解中配置sticky参数。
// 订阅粘性事件
@Subscribe(sticky = true)
public void onMessageEvent(myEvent me) {
...
}
// 粘性事件发布
EventBus.getDefault().postSticky(new myEvent ("This is sticky event"));
发布一个粘性事件之后,EventBus将在内存中缓存该粘性事件。当有订阅者订阅了该粘性事件,订阅者将接收到该事件。需要注意的是在未移除粘性事件之前,它会一直缓存在内存中,因此在处理完该事件后要及时移除该事件的缓存,移除粘性事件的方法如下:
// 移除指定的粘性事件
removeStickyEvent(Object event);
// 移除指定类型的粘性事件
removeStickyEvent(Class<T> eventType);
// 移除所有的粘性事件
removeAllStickyEvents();
5. EventBus中的优先级
在定义事件处理方法时,还可以在注解中设置该方法的优先级:
@Subscribe(priority = 1)
public void onEvent(myEvent me) {
...
}
默认情况下,订阅者方法的事件传递优先级为0。数值越大,优先级越高。在相同的线程模式下,更高优先级的订阅者方法将优先接收到事件。注意:优先级只有在相同的线程模式下才有效。