EventBus 3.0: 入门使用及其使用 完全解析
前言
EventBus是greenrobot再Android平台发布的以订阅-发布模式为核心的开源库。
EventBus翻译过来是事件总线意思。可以这样理解:一个个(event)发送到总线上,
然后EventBus根据已注册的订阅者(subscribers)来匹配相应的事件,进而把事件传递给订阅者,
这也是观察者模式的一个最佳实践。
我们平常开发中,当遇到Activity与Activity、Activity与Fragment之间的通信,往往采用intent,又
或者线程之间用Handler进行通信,这样代码会复杂很多,而使用EventBus极大简化两个组件之间俺的通信问题,
而且效率极高。而EventBus升级到3.0版本后,开发者能够自定义订阅方法名字,而没必要
规定以“o'n'Event'XX"开头的方法了,这样也自由化了很多,而且支持了粘性事件的分发等,因此学会使用EventBus3.0
对我们开发又极大的好处.
例子
布局
activity_main
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/tv_text"
android:textSize="20sp"
android:text="@string/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点击打开新的Activity"
android:id="@+id/secondActivityBtn"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="75dp" />
</RelativeLayout>
activity_second
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<EditText
android:id="@+id/et"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="请输入要发送的消息"
/>
<Button
android:id="@+id/sendMessageBtn"
android:text="发送消息"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
代码
public class MainActivity extends Activity {
private TextView textView;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注册成为订阅者
EventBus.getDefault().register(this);
textView = (TextView) findViewById(R.id.tv_text);
button = (Button) findViewById(R.id.secondActivityBtn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);
}
});
}
//订阅方法,当接收到事件的时候,会调用该方法
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent messageEvent){
Log.d("cylog","receive it");
textView.setText(messageEvent.getMessage());
Toast.makeText(MainActivity.this, messageEvent.getMessage(), Toast.LENGTH_SHORT).show();
}
@Override
protected void onDestroy() {
super.onDestroy();
//解除注册
EventBus.getDefault().unregister(this);
}
}
public class SecondActivity extends Activity {
private EditText et;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
et = findViewById(R.id.et);
Button button = (Button) findViewById(R.id.sendMessageBtn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(TextUtils.isEmpty(et.getText().toString())){
Toast.makeText(SecondActivity.this, "请输入......", Toast.LENGTH_SHORT).show();
return;
}else {
EventBus.getDefault().post(new MessageEvent(et.getText().toString()));
finish();
}
}
});
}
}
效果图
发送黏性事件Sticky Events
上面示例代码所说的情况是:当发送消息推送者推送消息的时候,订阅者会立马收到消息,它会把消息推送给它所有的订阅者.注意后面这句话:如果你希望在消息推送完成之后,让新注册的订阅者也能收到这条消息,这时候你可以试试Sticky Events,这个事件就像一个常驻广播,只要是有新的订阅者订阅了这个事件,就会收到消息.当然,有两点要求:
1.首先,发送的是黏性事件,代码将post改为postSticky
// EventBus.getDefault().post(new MessageEvent());
EventBus.getDefault().postSticky(new MessageEvent());
2.然后,订阅者要声明自己能够接收到黏性事件的消息:代码中@Subscribe注解中的sticky值为true,满足了这两点,就能愉快的玩耍了.
@Subscribe(sticky = true)
public void onMessageEvent(MessageEvent event) {
Log.i(TAG, "onMessageEvent: 我是sticky event 收到消息");
}
3.测试效果
把项目入口调整为ThridActivity
public class ThirdActivity extends Activity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
Button button1 = (Button) findViewById(R.id.sendStickyMessageBtn1);
Button button2 = (Button) findViewById(R.id.sendStickyMessageBtn2);
Button button3 = (Button) findViewById(R.id.sendStickyMessageBtn3);
Button button4 = (Button) findViewById(R.id.sendRegisterBtn);
button1.setOnClickListener(this);
button2.setOnClickListener(this);
button3.setOnClickListener(this);
button4.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.sendStickyMessageBtn1:
EventBus.getDefault().postSticky(new MessageEvent("粘性事件1"));
Log.e("cylog","发送粘性事件1...");
break;
case R.id.sendStickyMessageBtn2:
EventBus.getDefault().postSticky(new MessageEvent("粘性事件2"));
Log.e("cylog", "发送粘性事件2...");
break;
case R.id.sendStickyMessageBtn3:
EventBus.getDefault().postSticky(new MessageEvent("粘性事件3"));
Log.e("cylog", "发送粘性事件3...");
break;
case R.id.sendRegisterBtn:
Log.e("cylog", "注册成为订阅者...");
EventBus.getDefault().register(this);
break;
}
}
@Subscribe(sticky = true)
public void onEvent(MessageEvent messageEvent){
Log.e("cylog","接受到了来自EventBus的事件:"+messageEvent.getMessage());
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
那么很明显,只会接受到最后发送的粘性事件,在此之前的事件都接收不到。
线程模型
在EventBus的事件处理函数中需要指定线程模型,即指定事件处理函数运行所在的想线程。在上面我们已经接触到了EventBus的四种线程模型。那他们有什么区别呢?
在EventBus中的观察者通常有四种线程模型,分别是PostThread(默认)、MainThread、BackgroundThread与Async。
PostThread:如果使用事件处理函数指定了线程模型为PostThread,那么该事件在哪个线程发布出来的,事件处理函数就会在这个线程中运行,也就是说发布事件和接收事件在同一个线程。在线程模型为PostThread的事件处理函数中尽量避免执行耗时操作,因为它会阻塞事件的传递,甚至有可能会引起ANR。
MainThread:如果使用事件处理函数指定了线程模型为MainThread,那么不论事件是在哪个线程中发布出来的,该事件处理函数都会在UI线程中执行。该方法可以用来更新UI,但是不能处理耗时操作。
BackgroundThread:如果使用事件处理函数指定了线程模型为BackgroundThread,那么如果事件是在UI线程中发布出来的,那么该事件处理函数就会在新的线程中运行,如果事件本来就是子线程中发布出来的,那么该事件处理函数直接在发布事件的线程中执行。在此事件处理函数中禁止进行UI更新操作。
Async:如果使用事件处理函数指定了线程模型为Async,那么无论事件在哪个线程发布,该事件处理函数都会在新建的子线程中执行。同样,此事件处理函数中禁止进行UI更新操作。
为了验证以上四个方法,别人的例子
@Subscribe(threadMode = ThreadMode.PostThread)
public void onMessageEventPostThread(MessageEvent messageEvent) {
Log.e("PostThread", Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.MainThread)
public void onMessageEventMainThread(MessageEvent messageEvent) {
Log.e("MainThread", Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.BackgroundThread)
public void onMessageEventBackgroundThread(MessageEvent messageEvent) {
Log.e("BackgroundThread", Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.Async)
public void onMessageEventAsync(MessageEvent messageEvent) {
Log.e("Async", Thread.currentThread().getName());
}
分别使用上面四个方法订阅同一事件,打印他们运行所在的线程。首先我们在UI线程中发布一条MessageEvent的消息,看下日志打印结果是什么。
findViewById(R.id.send).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("postEvent", Thread.currentThread().getName());
EventBus.getDefault().post(new MessageEvent());
}
});
从日志打印结果可以看出,如果在UI线程中发布事件,则线程模型为PostThread的事件处理函数也执行在UI线程,与发布事件的线程一致。线程模型为Async的事件处理函数执行在名字叫做pool-1-thread-1的新的线程中。而MainThread的事件处理函数执行在UI线程,BackgroundThread的时间处理函数执行在名字叫做pool-1-thread-2的新的线程中。
我们再看看在子线程中发布一条MessageEvent的消息时,会有什么样的结果。
从日志打印结果可以看出,如果在子线程中发布事件,则线程模型为PostThread的事件处理函数也执行在子线程,与发布事件的线程一致(都是Thread-125)。BackgroundThread事件模型也与发布事件在同一线程执行。Async则在一个名叫pool-1-thread-1的新线程中执行。MainThread还是在UI线程中执行。
上面一个例子充分验证了指定不同线程模型的事件处理方法执行所在的线程。
EventBus 3.0: 入门使用及其使用 完全解析的更多相关文章
- 【热门技术】EventBus 3.0,让事件订阅更简单,从此告别组件消息传递烦恼~
一.写在前面 还在为时间接收而烦恼吗?还在为各种组件间的消息传递烦恼吗?EventBus 3.0,专注于android的发布.订阅事件总线,让各组件间的消息传递更简单!完美替代Intent,Handl ...
- Android消息传递之EventBus 3.0使用详解
前言: 前面两篇不仅学习了子线程与UI主线程之间的通信方式,也学习了如何实现组件之间通信,基于前面的知识我们今天来分析一下EventBus是如何管理事件总线的,EventBus到底是不是最佳方案?学习 ...
- Android EventBus 3.0.0 使用总结
转载请标明出处:http://www.cnblogs.com/zhaoyanjun/p/6039221.html 本文出自[赵彦军的博客] 前言 EventBus框架 EventBus是一个通用的叫法 ...
- ASP.NET Core 1.0 入门——了解一个空项目
var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...
- ASP.NET Core 1.0 入门——Application Startup
var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...
- EventBus 3.0使用
在没用eventBus之前一直用Android广播方式通知消息更新UI 广播写法 首先发送广播通知 Intent intent = new Intent(); intent.setAction(&qu ...
- Omnet++ 4.0 入门实例教程
http://blog.sina.com.cn/s/blog_8a2bb17d01018npf.html 在网上找到的一个讲解omnet++的实例, 是4.0下面实现的. 我在4.2上试了试,可以用. ...
- 《VC++ 6简明教程》即VC++ 6.0入门精讲 学习进度及笔记
VC++6.0入门→精讲 2013.06.09,目前,每一章的“自测题”和“小结”三个板块还没有看(备注:第一章的“实验”已经看完). 2013.06.16 第三章的“实验”.“自测题”.“小结”和“ ...
- spring web flow 2.0入门(转)
Spring Web Flow 2.0 入门 一.Spring Web Flow 入门demo(一)简单页面跳转 附源码(转) 二.Spring Web Flow 入门demo(二)与业务结合 附源码 ...
随机推荐
- CSS-标准盒模型 & 怪异盒模型
CSS中Box model分类 CSS中Box model是分为两种:: W3C标准 和 IE标准盒子模型. 大多数浏览器采用W3C标准模型,而IE中则采用Microsoft自己的标准. 怪异模式是“ ...
- oracle insert用法总结
总结下Oracle 中的Insert用法 1.标准Insert --单表单行插入 语法: INSERT INTO table [(column1,column2,...)] VALUE ...
- itchat 总结(转)
python实现微信接口(itchat) 安装 sudo pip install itchat 登录 itchat.auto_login() 这种方法将会通过微信扫描二维码登录,但是这种登录的方式确实 ...
- Windows Server 2012之活动目录域服务的卸载
Windows Server 2012之活动目录域服务的卸载 2012-07-11 06:27:35 标签:Windows Server 2012 活动目录域服务 卸载 原创作品,允许转载,转载时请务 ...
- NodeJs初学者经典入门解析
Node.js 是一个基于谷歌浏览器JavaScript执行环境建立的一个平台,让JavaScript可以脱离客户端浏览器运行,让 JavaScript具有服务器语言的能力.我们可以使用NodeJs方 ...
- IOS开发---菜鸟学习之路--(六)-UITableView几个方法的使用说明
对于UITableView的基础使用我这边就不做重复介绍了 我重点就来介绍下如何实现大部分新闻的界面.也就是第一条记录显示大图片下面加一段文字说明 然后剩下来的内容全部显示为文字图片的格式 其实要做到 ...
- 【Longest Substring Without Repeating Characters】cpp
题目: Given a string, find the length of the longest substring without repeating characters. For examp ...
- 微信小程序简单的数据表格及查询功能
简介: 此项目是一个前后端分离的小demo, 开发工具:idea+微信小程序开发工具 前端:界面布局样式和js的跳转 后端:依靠SpringBoot的业务逻辑层 项目的码云地址: https://gi ...
- mvc-自定义Route
public class CustomerRoute : RouteBase { //从路径中解析出controller.action以及其他参数,创建RouteData(其中包括HttpHandle ...
- [oldboy-django][2深入django]django一个请求的生命周期 + WSGI + 中间件
1 WSGI # WSGI(是一套协议,很多东西比如wsgiref, uwsgiref遵循这一套协议) - django系统本质 别人的socket(wsgiref或者uwsgiref) + djan ...