前言

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: 入门使用及其使用 完全解析的更多相关文章

  1. 【热门技术】EventBus 3.0,让事件订阅更简单,从此告别组件消息传递烦恼~

    一.写在前面 还在为时间接收而烦恼吗?还在为各种组件间的消息传递烦恼吗?EventBus 3.0,专注于android的发布.订阅事件总线,让各组件间的消息传递更简单!完美替代Intent,Handl ...

  2. Android消息传递之EventBus 3.0使用详解

    前言: 前面两篇不仅学习了子线程与UI主线程之间的通信方式,也学习了如何实现组件之间通信,基于前面的知识我们今天来分析一下EventBus是如何管理事件总线的,EventBus到底是不是最佳方案?学习 ...

  3. Android EventBus 3.0.0 使用总结

    转载请标明出处:http://www.cnblogs.com/zhaoyanjun/p/6039221.html 本文出自[赵彦军的博客] 前言 EventBus框架 EventBus是一个通用的叫法 ...

  4. ASP.NET Core 1.0 入门——了解一个空项目

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  5. ASP.NET Core 1.0 入门——Application Startup

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  6. EventBus 3.0使用

    在没用eventBus之前一直用Android广播方式通知消息更新UI 广播写法 首先发送广播通知 Intent intent = new Intent(); intent.setAction(&qu ...

  7. Omnet++ 4.0 入门实例教程

    http://blog.sina.com.cn/s/blog_8a2bb17d01018npf.html 在网上找到的一个讲解omnet++的实例, 是4.0下面实现的. 我在4.2上试了试,可以用. ...

  8. 《VC++ 6简明教程》即VC++ 6.0入门精讲 学习进度及笔记

    VC++6.0入门→精讲 2013.06.09,目前,每一章的“自测题”和“小结”三个板块还没有看(备注:第一章的“实验”已经看完). 2013.06.16 第三章的“实验”.“自测题”.“小结”和“ ...

  9. spring web flow 2.0入门(转)

    Spring Web Flow 2.0 入门 一.Spring Web Flow 入门demo(一)简单页面跳转 附源码(转) 二.Spring Web Flow 入门demo(二)与业务结合 附源码 ...

随机推荐

  1. web开发框架Flask学习二

    jinja2模板规范 在当前项目中创建一个文件为templates的文件夹,将其设置为模板文件夹,新建的html为模板页面, 在视图函数中使用render_template(".html的文 ...

  2. Ubuntu下Python无法识别中文

    在NLP的相关任务中,应用python处理中文是很常见的.在这个过程中,由于编码方式的不一致,可能会出现以下两种错误: 1)SyntaxError:  Non-ASCII character in f ...

  3. Git-Git基本操作

    先来合个影 马上就要和之前实践遗留的数据告别了,告别之前是不是要留个影呢?在Git里,"留影"用的命令叫做tag,更加专业的术语叫做"里程碑"(打tag,或打标 ...

  4. Java技术——Java多线程学习

    )适合多个相同程序代码的线程区处理同一资源的情况.比如下面这个买票的例子. //使用Thread实现 public static class MyThread extends Thread{ priv ...

  5. Python虚拟机类机制之填充tp_dict(二)

    填充tp_dict 在Python虚拟机类机制之对象模型(一)这一章中,我们介绍了Python的内置类型type如果要完成到class对象的转变,有一个重要的步骤就是填充tp_dict对象,这是一个极 ...

  6. 博客内插入bilibili视频

    原理 使用iframe标签,更改其中src的aid和cid,使其对应要插入的视频,即可在文章内插入bilibili视频 获取cid aid即为视频的av号,cid有两种获取方式,一是通过bilibil ...

  7. Leetcode 543.二叉树的直径

    二叉树的直径 给定一棵二叉树,你需要计算它的直径长度.一棵二叉树的直径长度是任意两个结点路径长度中的最大值.这条路径可能穿过根结点. 示例 :给定二叉树 1 / \ 2 3 / \ 4 5 返回 3, ...

  8. mysql数据库二进制初始化出现:170425 17:47:04 [ERROR] /application/mysql//bin/mysqld: unknown option '--skip-locking' 170425 17:47:04 [ERROR] Aborting 解决办法

    [root@localhost mysql]# ./scripts/mysql_install_db --user=mysql --basedir=/application/mysql/ --data ...

  9. PAT1033

    旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现.现在给出应该输入的一段文字.以及坏掉的那些键,打出的结果文字会是怎样? 输入格式: 输入在2行中分别给出坏掉的那些键.以及应该输入的文 ...

  10. BZOJ 1083:[SCOI2005]繁忙的都市(最小生成树)

    1083: [SCOI2005]繁忙的都市 Description 城市C是一个非常繁忙的大都市,城市中的道路十分的拥挤,于是市长决定对其中的道路进行改造.城市C的道路是这样分布的:城市中有n个交叉路 ...