消息处理之EventBus ——使用篇
以前的几篇文章简单的介绍了一下UI线程和子线程之间的线程通信利器Handler,以及顺便介绍了一下SyncTask和HeadlerThread。这里介绍另一线程通信利器EventBus。
EventBus是一个开源组件。https://github.com/greenrobot/EventBus,通过线程间事件订阅和分发来完成消息传递,通过这种模式来降低组件之间的耦合度。
多说无益,直接看实例。
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ public TextView myTextView;
private Button button0, button1, button2, button3;
private TestEventBus testEvent;
private int count = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTextView = (TextView)this.findViewById(R.id.text_view);
button0 = (Button)this.findViewById(R.id.post1);
button1 = (Button)this.findViewById(R.id.post2);
button2 = (Button)this.findViewById(R.id.post3);
button3 = (Button)this.findViewById(R.id.post4);
button0.setOnClickListener(this);
button1.setOnClickListener(this);
button2.setOnClickListener(this);
button3.setOnClickListener(this);
//测试线程启动
testEvent = new TestEventBus();
testEvent.start();
//订阅事件
EventBus.getDefault().register(this); } @Override
public void onClick(View v) {
int id = v.getId();
switch (id){
case R.id.post1:
MainEvent event = new MainEvent();
event.post = "come frome UI";
//UI线程中发送MainEvent类型事件
EventBus.getDefault().post(event);
break;
case R.id.post2:
new Thread(){
public void run(){
MainEvent event = new MainEvent();
event.post = "come frome Thread1";
//非UI线程中发送MainEvent类型事件
EventBus.getDefault().post(event);
}
}.start();
break;
case R.id.post3:
ThreadEvent event2 = new ThreadEvent();
event2.post = "come frome Thread2";
//UI线程送ThreadEvent类型事件
EventBus.getDefault().post(event2);
break;
case R.id.post4:
new Thread(){
public void run(){
ThreadEvent event = new ThreadEvent();
event.post = "come frome Thread2";
//非UI线程中发送ThreadEvent类型事件
EventBus.getDefault().post(event);
}
}.start();
break;
default:
break;
}
} @Override
protected void onDestroy() {
//注销该订阅
EventBus.getDefault().unregister(this);
testEvent.unregister();
super.onDestroy();
} /**
* 无论从那个线程发布的事件都会在UI线程中执行
* ThreadMode.MAIN
* @param event
* 对应低版本的onEventMainThread方法
*/
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onEventMain(MainEvent event) {
if(event != null){
String frome = event.post;
myTextView.setText(frome);
Log.e("Test", "onEventMainThread = " + frome);
}
} /**
* 无论从那个线程发布的事件,都在该线程中执行。
* 所以需要注意,不能执行耗时操作,避免ANR
* ThreadMode.POSTING
* @param event
* 对应低版本的onEvent
*/
@Subscribe(threadMode = ThreadMode.POSTING, sticky = true)
public void onEventPost(MainEvent event) {
if(event != null){
String frome = event.post;
Log.e("Test", "onEventPostThread = " + frome);
}
} /**
* 如果事件是从UI线程中发布出来,则在子线程中执行
* 如果事件本身是从子线程中出来,则仍然在该子线程中执行
* ThreadMode.BACKGROUND
* @param event
* 对应低版本的onEventBackgroundThread方法
*/
@Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true)
public void onEventBackground(MainEvent event) {
if(event != null){
String frome = event.post;
Log.e("Test", "onEventBackgroundThread = " + frome);
}
} /**
* 无论事件是从那个线程发布,都会另开一个线程执行
* 所以该方法永远不会在UI线程中被执行
* ThreadMode.ASYNC
* 对应低版本的onEventAsync
* @param event
*/
@Subscribe(threadMode = ThreadMode.ASYNC, sticky = true)
public void onEventAsync(MainEvent event) {
if(event != null){
String frome = event.post;
Log.e("Test", "onEventAsync = " + frome);
}
}
public class MainEvent{ public String post = "";
}
public class ThreadEvent{ public String post = "";
}
public class TestEventBus extends Thread{
public TestEventBus(){
//注册订阅
EventBus.getDefault().register(this);
}
public void unregister(){
//注销订阅
EventBus.getDefault().unregister(this);
}
public void run(){
while(true){}
}
/**
* 无论从那个线程发布的事件都会在UI线程中执行
* ThreadMode.MAIN
* @param event
* 对应低版本的onEventMainThread方法
*/
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onEventMainT(MainEvent event) {
if(event != null){
String frome = event.post;
myTextView.setText(frome);
Log.e("Test", "onEventMainThread_T = " + frome);
}
} /**
* 无论从那个线程发布的事件,都在该线程中执行。
* 所以需要注意,不能执行耗时操作,避免ANR
* ThreadMode.POSTING
* @param event
* 对应低版本的onEvent
*/
@Subscribe(threadMode = ThreadMode.POSTING, sticky = true)
public void onEventPostT(MainEvent event) {
if(event != null){
String frome = event.post;
Log.e("Test", "onEventPostThread_T = " + frome);
}
} /**
* 如果事件是从UI线程中发布出来,则在子线程中执行
* 如果事件本身是从子线程中出来,则仍然在该子线程中执行
* ThreadMode.BACKGROUND
* @param event
* 对应低版本的onEventBackgroundThread方法
*/
@Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true)
public void onEventBackgroundT(MainEvent event) {
if(event != null){
String frome = event.post;
Log.e("Test", "onEventBackgroundThread_T = " + frome);
}
} /**
* 无论事件是从那个线程发布,都会另开一个线程执行
* 所以该方法永远不会在UI线程中被执行
* ThreadMode.ASYNC
* 对应低版本的onEventAsync
* @param event
*/
@Subscribe(threadMode = ThreadMode.ASYNC, sticky = true)
public void onEventAsyncT(MainEvent event) {
if(event != null){
String frome = event.post;
Log.e("Test", "onEventAsync_T = " + frome);
}
}
/**
* 无论从那个线程发布的事件都会在UI线程中执行
* ThreadMode.MAIN
* @param event
* 对应低版本的onEventMainThread方法
*/
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onEventMainT(ThreadEvent event) {
if(event != null){
String frome = event.post;
myTextView.setText(frome);
Log.e("Test", "onEventMainThread_T = " + frome);
}
} /**
* 无论从那个线程发布的事件,都在该线程中执行。
* 所以需要注意,不能执行耗时操作,避免ANR
* ThreadMode.POSTING
* @param event
* 对应低版本的onEvent
*/
@Subscribe(threadMode = ThreadMode.POSTING, sticky = true)
public void onEventPostT(ThreadEvent event) {
if(event != null){
String frome = event.post;
Log.e("Test", "onEventPostThread_T = " + frome);
}
} /**
* 如果事件是从UI线程中发布出来,则在子线程中执行
* 如果事件本身是从子线程中出来,则仍然在该子线程中执行
* ThreadMode.BACKGROUND
* @param event
* 对应低版本的onEventBackgroundThread方法
*/
@Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true)
public void onEventBackgroundT(ThreadEvent event) {
if(event != null){
String frome = event.post;
Log.e("Test", "onEventBackgroundThread_T = " + frome);
}
} /**
* 无论事件是从那个线程发布,都会另开一个线程执行
* 所以该方法永远不会在UI线程中被执行
* ThreadMode.ASYNC
* 对应低版本的onEventAsync
* @param event
*/
@Subscribe(threadMode = ThreadMode.ASYNC, sticky = true)
public void onEventAsyncT(ThreadEvent event) {
if(event != null){
String frome = event.post;
Log.e("Test", "onEventAsync_T = " + frome);
}
}
} }
不好意思,例子有点大啊。但是覆盖已经比较全了。
首先,按照订阅的模式,我们发现在主线程里面有订阅(第34行代码)和退订(第82行代码),那么都订阅了那种类型的事件?根据第94,110,125,140行代码定义的方法可以看出有相同的参数类型MainEvent。
其次,还有一个线程TestEventBus 在第32行开始运行。该线程里也有订阅(157行)和退订(161行),而该线程却订阅了两种类型的事件。一个类型是MainEvent(第173,189,203,219行方法中定义的参数类型),另一个类型是TreadEvent(第232,248,263,277行方法中定义的参数)。
好现在开始运行。
先点击第一个按钮POST1,在主线程中发送一个MainEvent事件,内容为“come frome UI” 执行结果如下:
test.handler.andorid.com.handlertestactivity E/Test: onEventAsync_T = come frome UI
test.handler.andorid.com.handlertestactivity E/Test: onEventMainThread_T = come frome UI
test.handler.andorid.com.handlertestactivity E/Test: onEventPostThread_T = come frome UI
test.handler.andorid.com.handlertestactivity E/Test: onEventMainThread = come frome UI
test.handler.andorid.com.handlertestactivity E/Test: onEventBackgroundThread_T = come frome UI
test.handler.andorid.com.handlertestactivity E/Test: onEventPostThread = come frome UI
test.handler.andorid.com.handlertestactivity E/Test: onEventBackgroundThread = come frome UI
test.handler.andorid.com.handlertestactivity E/Test: onEventAsync = come frome UI
可以看到凡是订阅了MainEvent类型的方法的地方,无论是在子线程还是UI线程,都会被执行。
说明事件的分发本身不会线程做任何挑剔,只要订阅了,就会分发。
点第二个按钮POST2,在非主线程中发送MainEvent事件,内容为“come frome Thread1”。运行结果如下:
test.handler.andorid.com.handlertestactivity E/Test: onEventBackgroundThread_T = come frome Thread1
test.handler.andorid.com.handlertestactivity E/Test: onEventAsync_T = come frome Thread1
test.handler.andorid.com.handlertestactivity E/Test: onEventPostThread_T = come frome Thread1
test.handler.andorid.com.handlertestactivity E/Test: onEventBackgroundThread = come frome Thread1
test.handler.andorid.com.handlertestactivity E/Test: onEventAsync = come frome Thread1
test.handler.andorid.com.handlertestactivity E/Test: onEventPostThread = come frome Thread1
test.handler.andorid.com.handlertestactivity E/Test: onEventMainThread_T = come frome Thread1
test.handler.andorid.com.handlertestactivity E/Test: onEventMainThread = come frome Thread1
可以看见,这次结果和从UI线程中发事件结果相同。这说明一点,事件接收者并不挑剔事件是从那个线程发出来。
点第三个按钮POST3,在主线程中发送ThreadEvent事件。内容为“come frome Thread2” 。运行结果如下:
test.handler.andorid.com.handlertestactivity E/Test: onEventAsync_T = come frome Thread2
test.handler.andorid.com.handlertestactivity E/Test: onEventBackgroundThread_T = come frome Thread2
test.handler.andorid.com.handlertestactivity E/Test: onEventMainThread_T = come frome Thread2
test.handler.andorid.com.handlertestactivity E/Test: onEventPostThread_T = come frome Thread2
由于主线程里面没有订阅ThreadEvent事件,而TestEventBus订阅了ThreadEvent事件,所以,所以在TestEventBus中做了处理,但是UI线程没有收到该事件。
这说明事件分发者分发一个事件时,只给有能力处理该事件类型的订阅者分发。
第四个按钮POST4,先不点击,可以预估一下运行结果............
貌似好简单,首先进行订阅,然后实现处理方法就可以了。但是有个不好的消息,订阅者的处理方法不一定会在订阅者线程中执行。具体的在哪里执行,可以看到代码注释,这里在详细说明一下。
第一种,在低版本的EventBus沿用的方法是onEventMainThread(Event),在EventBus3.0版本则方法可以任意定义,但是接受事件类型需要在参数中说清楚。此外定义的模式为ThreandMod.MAIN。任何版本EventBus,这都表示无论事件发送者在那个线程,接受者都在主线程中运行
第二种,在低版本的EventBus沿用的方法是onEventBackgroundThread(Event),在EventBus3.0 则定义的模式是ThreadMode.BACKGROUND。 任何版本EventBus,
都表示无论是那个线程发出来的事件,如果该线程是后台线程(非主线程)则在该线程中执行。如果是主线程发出来的,则开启新线程执行。
第三种,在低版本的EventBus沿用的方法是onEvent(Event), 在3.0版本则定义的模式是ThreadMode.POSTING。任何版本的EventBus都表示从那个线程发送的事件,都会由该线程执行。
第四种,在低版本的EventBus沿用的方法是onEventAsync,在3.0版本则定义的模式是ThreadMode.ASYNC。表示无论从那个线程发布出来的事件,都重新开启线程执行。
好了,今天就到这里吧。明天再说EventBus的原理。
消息处理之EventBus ——使用篇的更多相关文章
- Android消息处理:EventBus、BroadCast和Handler-优缺点比较
上一篇研究了EventBus的使用方法,但随之而来的一系列问题也是值得思考,EventBus到底给项目带来了什么?它与Android原有的消息处理机制有什么区别和优缺点?项目在什么场景下采用Event ...
- EventBus 基础篇
最近在研究RxJava ,突然想起了事件分发另一个强大的框架Eventbus ,并且项目经常用到,特意整理了下. what is Eventbus? 官方的解释为: EventBus is a pub ...
- Android学习系列(43)--使用事件总线框架EventBus和Otto
事件总线框架 针对事件提供统一订阅,发布以达到组件间通信的解决方案. 原理 观察者模式. EventBus和Otto 先看EventBus的官方定义: Android optimized event ...
- 羽夏看Win系统内核——消息机制篇
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...
- Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理
Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理 前言 上一篇分析了BeanFactoryPostProcessor的作用,那么这一篇继续 ...
- 全球最低功耗蓝牙单芯片DA14580的软件体系 -层次架构和BLE消息事件处理过程
在作者之前发表的<全球最低功耗蓝牙单芯片DA14580的系统架构和应用开发框架分析>.<全球最低功耗蓝牙单芯片DA14580的硬件架构和低功耗>.<全球最低功耗蓝牙单芯片 ...
- Android 12(S) 图形显示系统 - SurfaceFlinger的启动和消息队列处理机制(四)
1 前言 SurfaceFlinger作为Android图形显示系统处理逻辑的核心单元,我们有必要去了解其是如何启动,初始化及进行消息处理的.这篇文章我们就来简单分析SurfaceFlinger这个B ...
- TGL站长关于常见问题的回复
问题地址: http://www.thegrouplet.com/thread-112923-1-1.html 问题: 网站配有太多的模板是否影响网站加载速度 月光答复: wp不需要删除其他的模板,不 ...
- 快速Android开发系列通信篇之EventBus
先吐槽一下博客园的MarkDown编辑器,推出的时候还很高兴博客园支持MarkDown了,试用了下发现支持不完善就没用了,这次这篇是在其他编辑器下写的,复制过来后发现..太烂了.怎么着作为一个技术博客 ...
随机推荐
- 【转】 Android SDK无法更新解决方法---不错
原文网址:http://blog.csdn.net/shi_weihappy/article/details/41847997 自己的修改: 203.208.39.238 dl.google.com7 ...
- ASP.NET中验证控件的使用
转自:http://www.cnblogs.com/yangmingming/archive/2010/03/09/1682006.html 前言: 前几日,无奈用JS判断控件的有效性,发现的确是一件 ...
- 提高IIS的并发量
IIS 7.0使用的是默认配置,服务器最多只能处理5000个同时请求. 根据相关文档调整设置,可以让服务器从设置上支持10万个同时请求 . 调整IIS 7应用程序池队列长度 由原来的默认1000改为6 ...
- arcGis引入Dll报无法嵌入互操作类型错误解决方法
arcGis引入Dll报“无法嵌入互操作类型"ESRI.ARCGIS.Geometry.PointClass".请改用通用接口." 解决方法:设置引用DLL的“嵌入互 ...
- 解决eclipse插件svn不显示svn信息和显示的信息为数字的问题
1.选择window-->preferences如下图 通过上面步骤svn信息便显示了 2.解决显示的信息为数字问题 选择svn-label decoration format里面的author ...
- bat坐拥大数据。数据挖掘/大数据给他们带来什么。
阿里巴巴CTO即阿里云负责人王坚博士说过一句话:云计算和大数据,你们都理解错了. 实际上,对于大数据究竟是什么业界并无共识.大数据并不是什么新鲜事物.信息革命带来的除了信息的更高效地生产.流通和消 ...
- NOI2007 货币兑换
[问题描述] 小 Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和B纪念券(以下简称B券).每个持有金券的顾客都有一个自己的 帐户.金券的数目可以是一个实数.每天 ...
- 如何在 CentOS 7 上安装 Redis 服务器
大家好,本文的主题是 Redis,我们将要在 CentOS 7 上安装它.编译源代码,安装二进制文件,创建.安装文件.在安装了它的组件之后,我们还会配置 redis ,就像配置操作系统参数一样,目标就 ...
- Java Web学习笔记-Servlet不是线程安全的
由于Servlet只会有一个实例,多个用户同时请求同一个Servlet时,Tomcat会派生出多条线程执行Servlet的代码,因此Servlet有线程不安全的隐患.如果设计不当,系统就会出现问题. ...
- TI-Davinci开发系列之二使用CCS5.2TI Simulator模拟环境调试DSP程序
上接博文<TI-Davinci开发系列之一CCS5.2的安装及注意事项>. 如何没有实际的开发板或者仿真器,可以使用CCS自带的TISimulator来学习与熟悉CCS开发调试环境.下面是 ...