消息处理之EventBus ——使用篇

以前的几篇文章简单的介绍了一下UI线程和子线程之间的线程通信利器Handler,以及顺便介绍了一下SyncTask和HeadlerThread。这里介绍另一线程通信利器EventBus。

EventBus是一个开源组件。https://github.com/greenrobot/EventBus,通过线程间事件订阅和分发来完成消息传递,通过这种模式来降低组件之间的耦合度。

多说无益,直接看实例。

  1 import android.support.v7.app.AppCompatActivity;
  2 import android.os.Bundle;
  3 import android.util.Log;
  4 import android.view.View;
  5 import android.widget.Button;
  6 import android.widget.TextView;
  7 import org.greenrobot.eventbus.EventBus;
  8 import org.greenrobot.eventbus.Subscribe;
  9 import org.greenrobot.eventbus.ThreadMode;
 10
 11 public class MainActivity extends AppCompatActivity implements View.OnClickListener{
 12
 13     public TextView myTextView;
 14     private Button button0, button1, button2, button3;
 15     private TestEventBus testEvent;
 16     private int count = 0;
 17     @Override
 18     public void onCreate(Bundle savedInstanceState) {
 19         super.onCreate(savedInstanceState);
 20         setContentView(R.layout.activity_main);
 21         myTextView = (TextView)this.findViewById(R.id.text_view);
 22         button0 = (Button)this.findViewById(R.id.post1);
 23         button1 = (Button)this.findViewById(R.id.post2);
 24         button2 = (Button)this.findViewById(R.id.post3);
 25         button3 = (Button)this.findViewById(R.id.post4);
 26         button0.setOnClickListener(this);
 27         button1.setOnClickListener(this);
 28         button2.setOnClickListener(this);
 29         button3.setOnClickListener(this);
 30         //测试线程启动
 31         testEvent = new TestEventBus();
 32         testEvent.start();
 33         //订阅事件
 34         EventBus.getDefault().register(this);
 35
 36     }
 37
 38     @Override
 39     public void onClick(View v) {
 40         int id = v.getId();
 41         switch (id){
 42             case R.id.post1:
 43                 MainEvent event = new MainEvent();
 44                 event.post = "come frome UI";
 45                 //UI线程中发送MainEvent类型事件
 46                 EventBus.getDefault().post(event);
 47                 break;
 48             case R.id.post2:
 49                 new Thread(){
 50                     public void run(){
 51                         MainEvent event = new MainEvent();
 52                         event.post = "come frome Thread1";
 53                         //非UI线程中发送MainEvent类型事件
 54                         EventBus.getDefault().post(event);
 55                     }
 56                 }.start();
 57                 break;
 58             case R.id.post3:
 59                 ThreadEvent event2 = new ThreadEvent();
 60                 event2.post = "come frome Thread2";
 61                 //UI线程送ThreadEvent类型事件
 62                 EventBus.getDefault().post(event2);
 63                 break;
 64             case R.id.post4:
 65                 new Thread(){
 66                     public void run(){
 67                         ThreadEvent event = new ThreadEvent();
 68                         event.post = "come frome Thread2";
 69                         //非UI线程中发送ThreadEvent类型事件
 70                         EventBus.getDefault().post(event);
 71                     }
 72                 }.start();
 73                 break;
 74             default:
 75                 break;
 76         }
 77     }
 78
 79     @Override
 80     protected void onDestroy() {
 81         //注销该订阅
 82         EventBus.getDefault().unregister(this);
 83         testEvent.unregister();
 84         super.onDestroy();
 85     }
 86
 87     /**
 88      * 无论从那个线程发布的事件都会在UI线程中执行
 89      * ThreadMode.MAIN
 90      * @param event
 91      * 对应低版本的onEventMainThread方法
 92      */
 93     @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
 94     public void onEventMain(MainEvent event) {
 95         if(event != null){
 96             String frome = event.post;
 97             myTextView.setText(frome);
 98             Log.e("Test", "onEventMainThread = " + frome);
 99         }
100     }
101
102     /**
103      * 无论从那个线程发布的事件,都在该线程中执行。
104      * 所以需要注意,不能执行耗时操作,避免ANR
105      * ThreadMode.POSTING
106      * @param event
107      * 对应低版本的onEvent
108      */
109     @Subscribe(threadMode = ThreadMode.POSTING, sticky = true)
110     public void onEventPost(MainEvent event) {
111         if(event != null){
112             String frome = event.post;
113             Log.e("Test", "onEventPostThread = " + frome);
114         }
115     }
116
117     /**
118      * 如果事件是从UI线程中发布出来,则在子线程中执行
119      * 如果事件本身是从子线程中出来,则仍然在该子线程中执行
120      * ThreadMode.BACKGROUND
121      * @param event
122      * 对应低版本的onEventBackgroundThread方法
123      */
124     @Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true)
125     public void onEventBackground(MainEvent event) {
126         if(event != null){
127             String frome = event.post;
128             Log.e("Test", "onEventBackgroundThread = " + frome);
129         }
130     }
131
132     /**
133      * 无论事件是从那个线程发布,都会另开一个线程执行
134      * 所以该方法永远不会在UI线程中被执行
135      * ThreadMode.ASYNC
136      * 对应低版本的onEventAsync
137      * @param event
138      */
139     @Subscribe(threadMode = ThreadMode.ASYNC, sticky = true)
140     public void onEventAsync(MainEvent event) {
141         if(event != null){
142             String frome = event.post;
143             Log.e("Test", "onEventAsync = " + frome);
144         }
145     }
146     public class MainEvent{
147
148         public String post = "";
149     }
150     public class ThreadEvent{
151
152         public String post = "";
153     }
154     public class TestEventBus extends Thread{
155         public TestEventBus(){
156             //注册订阅
157             EventBus.getDefault().register(this);
158         }
159         public void unregister(){
160             //注销订阅
161             EventBus.getDefault().unregister(this);
162         }
163         public void run(){
164             while(true){}
165         }
166         /**
167          * 无论从那个线程发布的事件都会在UI线程中执行
168          * ThreadMode.MAIN
169          * @param event
170          * 对应低版本的onEventMainThread方法
171          */
172         @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
173         public void onEventMainT(MainEvent event) {
174             if(event != null){
175                 String frome = event.post;
176                 myTextView.setText(frome);
177                 Log.e("Test", "onEventMainThread_T = " + frome);
178             }
179         }
180
181         /**
182          * 无论从那个线程发布的事件,都在该线程中执行。
183          * 所以需要注意,不能执行耗时操作,避免ANR
184          * ThreadMode.POSTING
185          * @param event
186          * 对应低版本的onEvent
187          */
188         @Subscribe(threadMode = ThreadMode.POSTING, sticky = true)
189         public void onEventPostT(MainEvent event) {
190             if(event != null){
191                 String frome = event.post;
192                 Log.e("Test", "onEventPostThread_T = " + frome);
193             }
194         }
195
196         /**
197          * 如果事件是从UI线程中发布出来,则在子线程中执行
198          * 如果事件本身是从子线程中出来,则仍然在该子线程中执行
199          * ThreadMode.BACKGROUND
200          * @param event
201          * 对应低版本的onEventBackgroundThread方法
202          */
203         @Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true)
204         public void onEventBackgroundT(MainEvent event) {
205             if(event != null){
206                 String frome = event.post;
207                 Log.e("Test", "onEventBackgroundThread_T = " + frome);
208             }
209         }
210
211         /**
212          * 无论事件是从那个线程发布,都会另开一个线程执行
213          * 所以该方法永远不会在UI线程中被执行
214          * ThreadMode.ASYNC
215          * 对应低版本的onEventAsync
216          * @param event
217          */
218         @Subscribe(threadMode = ThreadMode.ASYNC, sticky = true)
219         public void onEventAsyncT(MainEvent event) {
220             if(event != null){
221                 String frome = event.post;
222                 Log.e("Test", "onEventAsync_T = " + frome);
223             }
224         }
225         /**
226          * 无论从那个线程发布的事件都会在UI线程中执行
227          * ThreadMode.MAIN
228          * @param event
229          * 对应低版本的onEventMainThread方法
230          */
231         @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
232         public void onEventMainT(ThreadEvent event) {
233             if(event != null){
234                 String frome = event.post;
235                 myTextView.setText(frome);
236                 Log.e("Test", "onEventMainThread_T = " + frome);
237             }
238         }
239
240         /**
241          * 无论从那个线程发布的事件,都在该线程中执行。
242          * 所以需要注意,不能执行耗时操作,避免ANR
243          * ThreadMode.POSTING
244          * @param event
245          * 对应低版本的onEvent
246          */
247         @Subscribe(threadMode = ThreadMode.POSTING, sticky = true)
248         public void onEventPostT(ThreadEvent event) {
249             if(event != null){
250                 String frome = event.post;
251                 Log.e("Test", "onEventPostThread_T = " + frome);
252             }
253         }
254
255         /**
256          * 如果事件是从UI线程中发布出来,则在子线程中执行
257          * 如果事件本身是从子线程中出来,则仍然在该子线程中执行
258          * ThreadMode.BACKGROUND
259          * @param event
260          * 对应低版本的onEventBackgroundThread方法
261          */
262         @Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true)
263         public void onEventBackgroundT(ThreadEvent event) {
264             if(event != null){
265                 String frome = event.post;
266                 Log.e("Test", "onEventBackgroundThread_T = " + frome);
267             }
268         }
269
270         /**
271          * 无论事件是从那个线程发布,都会另开一个线程执行
272          * 所以该方法永远不会在UI线程中被执行
273          * ThreadMode.ASYNC
274          * 对应低版本的onEventAsync
275          * @param event
276          */
277         @Subscribe(threadMode = ThreadMode.ASYNC, sticky = true)
278         public void onEventAsyncT(ThreadEvent event) {
279             if(event != null){
280                 String frome = event.post;
281                 Log.e("Test", "onEventAsync_T = " + frome);
282             }
283         }
284     }
285
286 }

不好意思,例子有点大啊。但是覆盖已经比较全了。

首先,按照订阅的模式,我们发现在主线程里面有订阅(第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” 执行结果如下:

1 test.handler.andorid.com.handlertestactivity E/Test: onEventAsync_T = come frome UI
2 test.handler.andorid.com.handlertestactivity E/Test: onEventMainThread_T = come frome UI
3 test.handler.andorid.com.handlertestactivity E/Test: onEventPostThread_T = come frome UI
4 test.handler.andorid.com.handlertestactivity E/Test: onEventMainThread = come frome UI
5 test.handler.andorid.com.handlertestactivity E/Test: onEventBackgroundThread_T = come frome UI
6 test.handler.andorid.com.handlertestactivity E/Test: onEventPostThread = come frome UI
7 test.handler.andorid.com.handlertestactivity E/Test: onEventBackgroundThread = come frome UI
8 test.handler.andorid.com.handlertestactivity E/Test: onEventAsync = come frome UI

可以看到凡是订阅了MainEvent类型的方法的地方,无论是在子线程还是UI线程,都会被执行。

说明事件的分发本身不会线程做任何挑剔,只要订阅了,就会分发。

点第二个按钮POST2,在非主线程中发送MainEvent事件,内容为“come frome Thread1”。运行结果如下:

1 test.handler.andorid.com.handlertestactivity E/Test: onEventBackgroundThread_T = come frome Thread1
2 test.handler.andorid.com.handlertestactivity E/Test: onEventAsync_T = come frome Thread1
3 test.handler.andorid.com.handlertestactivity E/Test: onEventPostThread_T = come frome Thread1
4 test.handler.andorid.com.handlertestactivity E/Test: onEventBackgroundThread = come frome Thread1
5 test.handler.andorid.com.handlertestactivity E/Test: onEventAsync = come frome Thread1
6 test.handler.andorid.com.handlertestactivity E/Test: onEventPostThread = come frome Thread1
7 test.handler.andorid.com.handlertestactivity E/Test: onEventMainThread_T = come frome Thread1
8 test.handler.andorid.com.handlertestactivity E/Test: onEventMainThread = come frome Thread1

可以看见,这次结果和从UI线程中发事件结果相同。这说明一点,事件接收者并不挑剔事件是从那个线程发出来。

点第三个按钮POST3,在主线程中发送ThreadEvent事件。内容为“come frome Thread2” 。运行结果如下:

1 test.handler.andorid.com.handlertestactivity E/Test: onEventAsync_T = come frome Thread2
2 test.handler.andorid.com.handlertestactivity E/Test: onEventBackgroundThread_T = come frome Thread2
3 test.handler.andorid.com.handlertestactivity E/Test: onEventMainThread_T = come frome Thread2
4 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的原理。

时间: 2024-10-25 18:23:13

消息处理之EventBus ——使用篇的相关文章

Android学习系列(43)--使用事件总线框架EventBus和Otto

事件总线框架 针对事件提供统一订阅,发布以达到组件间通信的解决方案. 原理 观察者模式. EventBus和Otto 先看EventBus的官方定义: Android optimized event bus that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality. 再看Otto官方定义: Otto is an event bus d

全球最低功耗蓝牙单芯片DA14580的软件体系 -层次架构和BLE消息事件处理过程

在作者之前发表的<全球最低功耗蓝牙单芯片DA14580的系统架构和应用开发框架分析>.<全球最低功耗蓝牙单芯片DA14580的硬件架构和低功耗>.<全球最低功耗蓝牙单芯片DA14580的软件体系-RW内核和消息处理机制>三篇文章分析了DA14580的SDK开发目录结构.硬件架构.低功耗.RW内核和消息处理机制.本篇文章将深入到具体的源码去分析DA14580平台的软件层次架构和具体的BLE消息处理过程,以此佐证前面发表的文章. 一.软件层次架构 1.1 BLE协议栈 从中

诗经 全文

诗经 全文 (带注释和译文) http://www.edu009.com/Article/HTML/Article_60756.html <诗经> 春秋·孔丘 <诗经>是我国第一部诗歌总集,先秦时代称为“诗”或“诗三百”,孔子加以了整理.汉武帝采纳董仲舒“罢黜百家,独尊儒术”的建议,尊“诗”为经典,定名为<诗经>. <诗经>现存诗歌 305 篇,包括西周初年到春秋中叶共 500 余年的民歌和朝庙乐章,分为风.雅.颂三章. “风”包括周南.召南.邶.鄘.卫.王

Win32编程API 基础篇 -- 3.消息处理 根据英文教程翻译

消息处理 例子:窗口点击 好的,现在我们已经得到一个窗口了,但我们什么也做不了除了DefWindowProc()允许窗口大小被调整,最大最小化等...这不是很激动人心啊 在接下来的一小节中我将向你展示如何修改现有的程序,让它做一些新的事情,这样我就可以告诉你,“处理消息然后这样做...”,我会明白我的意思是什么并且在不需要看完完整的栗子的基础上完成它.所以不管怎样,集中注意力 OK,对初学者来说拿最近的一个窗口程序的代码,保证编译通过并且正常运行,然后你就可以在这份代码的基础上进行一些小修改,或

EventBus 这一篇还不够

参考网站 环境配置 原理介绍 入门例子 定义 MessageEvent 对象 定义 处理 MessageEvent对象方法 注册和取消订阅 发布MessageEvent 理清思路 ThreadMode 介绍 EventBus其他功能介绍 StickyEvent 订阅权限 Subscriber Priorities 取消事件分发 还有其他的就自己看官网吧 写在最后的话 参考网站 EventBus 官网 环境配置 Gradle: compile 'org.greenrobot:eventbus:3.

[android架构篇]mvp+rxjava+retrofit+eventBus

android架构篇 mvp+rxjava+retrofit+eventBus 高层不应该知道低层的细节,应该是面向抽象的编程.业务的实现交给实现的接口的类.高层只负责调用. 首先,要介绍一下一个项目中好架构的好处:好的软件设计必须能够帮助开发者发展和扩充解决方案,保持代码清晰健壮,并且可扩展,易于维护,而不必每件事都重写代码.面对软件存在的问题,必须遵守SOLID原则(面向对象五大原则),不要过度工程化,尽可能降低框架中模块的依赖性. 之前的一段时间,学习了一些新的技术,并把自己关注的技术整合

[028] 微信公众帐号开发教程第4篇-消息及消息处理工具的封装

工欲善其事必先利其器!本篇内容主要讲解如何将微信公众平台定义的消息及消息相关的操作封装成工具类,方面后期的使用.这里需要明确的是消息其实是由用户发给你的公众帐号的,消息先被微信平台接收到,然后微信平台会将该消息转给你在开发模式接口配置中指定的URL地址. 微信公众平台消息接口 要接收微信平台发送的消息,我们需要先熟悉微信公众平台API中消息接口部分,点此进入,点击后将进入到消息接口指南部分,如下图所示: 在上图左侧可以看到微信公众平台目前开放的接口有三种:消息接口.通用接口和自定义菜单接口.通用

快速Android开发系列通信篇之EventBus

概述及基本概念 **EventBus**是一个Android端优化的publish/subscribe消息总线,简化了应用程序内各组件间.组件与后台线程间的通信.比如请求网络,等网络返回时通过Handler或Broadcast通知UI,两个Fragment之间需要通过Listener通信,这些需求都可以通过**EventBus**实现. 作为一个消息总线,有三个主要的元素: Event:事件 Subscriber:事件订阅者,接收特定的事件 Publisher:事件发布者,用于通知Subscri

EventBus组件间通讯利器【入门篇】

一.概述 EventBus是一款针对Android优化的公布/订阅事件总线.主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service.线程之间传递消息.长处是开销小.代码更优雅.以及将发送者和接收者解耦. 比方假设多层的Fragment之间的通讯,通讯起来就是比較麻烦的,假设重复使用 自己定义广播的话就会造成软件性能的下降.EventBus的出现便非常好的解决的这个问题,使用它你能够非常方便的让各组件之间进行通讯,而不会占用太多的内存.仅