到看到网页上蛇的照片差点把手机扔了,为什么

Android 中 EventBus 的使用(二):缓存事件 - Android当前位置:& &&&Android 中 EventBus 的使用(二):缓存事件Android 中 EventBus 的使用(二):缓存事件&&网友分享于:&&浏览:0次Android 中 EventBus 的使用(2):缓存事件在中,我曾提到我所选择的是Green Robot提供的EventBus(Android平台),而且这并非只是我一个人的选择。在最近一次查看中,我发现选择它的人数已经是Otto(由Jake Wharton和其他大神们在Square上所提供的版本)的两倍之多了。GR的版本显然比Otto有更多的性能提升,但最令我动心的地方在于它添加了很多新功能。今天我就打算谈谈其中的一项:通过sticky事件进行事件缓存。
sticky是什么?
sticky事件就是指在EventBus内部被缓存的那些事件。EventBus为每个类(class)类型保存了最近一次被发送的事件&&sticky。后续被发送过来的相同类型的sticky事件会自动替换之前缓存的事件。当一个监听者向EventBus进行注册时,它可能会去请求这些缓存事件。这时,所有已缓存的事件就会立即自动发送给这个监听者,就象这些事件又重新刚被发送了一次一样。这就意味着,一个监听者可以收到在它注册之前就已经被发送到EventBus中的事件(甚至是在这个监听者的实例被创建出来前,这一点是不是很奇妙)。这一强大功能将有助于我们解决某些固有的问题,如Android上跨Activity和Fragment生命周期传递数据这种复杂问题,异步调用等等。
使用sticky使用sticky事件需要从两个方面进行:
一、发送者必须通过调用bus.postSticky(event)将事件进行缓存。
二、监听者须调用bus.registerSticky(this)以获取缓存的事件。
当调用了bus.registerSticky(this)后,监听者会立即收到所有已在onEvent处理程序中定义过的那些已缓存的事件。另外,监听者也可以根据需要通过bus.getStickyEvent(SomeEvent.class)来获取这些缓存事件。
(注:调用postSticky,会像普通的post调用一样将事件发送给所有当前活动的监听者,而不是仅限于那些通过registerSticky注册的。registerSticky仅仅是使缓存事件在注册时被重发。)
sticky事件在缓存中存在的时间并不确定。所以如果你想在某一时刻消除缓存中的事件好让它们不再被发送,可以通过bus.removeStickyEvent(event)或bus.removeStickyEvent(SomeEvent.class),以及bus.removeAllStickyEvents()来实现。
令人厌恶的Bundles
我在中曾说过,我并不喜欢Android中的Bundle,而且尽量避免使用它们。我不喜欢被象Serializable或者是Parcelable这类对象所约束,尤其是它们还缺少对类型安全的检查。我的意思是必竟这是Java,而不是Python或者Javascript什么的。我希望我的IDE能够发现并告诉我这样的错误,如一个组件向另外一个组件发送了一个不是它期望的对象类型。
不要误会,Intent在进程间通信时还是很有用的,在这种情况下将携带的数据序列化成通用格式是合情合理的。但如果仅仅是为了在用户旋转了一下屏幕后,让程序保持原来的状态,以科学的名义说,有必要非得用这种方法么?没错,我说的就是Android提供的处理配置改变的标准模式&&在onSaveInstanceState(Bundle bundle)和onRestoreInstanceState(Bundle bundle)中保存和恢复状态数据。且不提那些荒唐复杂的Fragment生命周期问题,单单是保持运行状态的这种处理方式就是我最不喜欢的Android开发特点之一。
Stinky Bundles Sticky Events
程序运行状态除了保存到Bundle中,另一种方法是将它们保存到某些在配置改变时依然生存着的对象中去。GR的EventBus刚好内置了这种缓存机制可供我们使用。
考虑下面这个响应&Master/Detail流程&的标准场景:
有一个List组件(通常为Fragment)显示一个摘要列表。
另外一个组件(另一个Fragment)显示每一项的详细内容。
点击某一列表项可显示对应的详细信息。
在竖屏模式中,列表和详细信息分为两页,各占一屏,每次只能看到一个页面。
在横屏模式中,列表在屏幕的左侧,详细信息在右侧,当左侧的列表项被选中时,右侧的详细信息也随之改变。
主Activity中包含一个布局(layout)用于在不同模式下进行切换。
在这个例子中具有挑战性的是,当用户在横竖屏间来回切换时,程序要如何维护当前所选项的状态。这个状态的重要性不但在于详细页面需要知道该显示哪条详细信息,而且列表也需要显示出当前哪一项被选中了。此外,对于主页面来说也需要知道当前是否有项目被选中,以便决定在竖屏模式时需要加载哪个页面,列表或详细信息。
如你所见,这三个组件都需要同一个状态信息(被选中项)。使用传统方法,这三个组件每一个都需要在各自的onSaveInstanceState方法中将这一状态保存进Bundle中,然后再从各自的onResumeInstanceState方法里把数据取回来。不爽!
然而使用sticky事件,事情就变得简单多了。为了更好地说明问题,我创建了一个Android示例工程:/wongcain/EventBus-Config-Demo/ 下面所有的示例代码都包含在这个工程里。
首先,创建一个事件类(ItemSelectedEvent.java)用于传递被选中项的位置信息:
public class ItemSelectedEvent {
public final int position;
public ItemSelectedEvent(int position) {
this.position = position;
然后在List组件(ItemListFragment.java)的listItemClick方法里发送一个sticky事件:
public void onListItemClick(ListView listView, View itemView, int position, long id) {
super.onListItemClick(listView, itemView, position, id);
bus.postSticky(new ItemSelectedEvent(position));
接下来,Detail组件(ItemDetailFragment.java)注册接收sticky事件,并定义一个ItemSelectedEvent的处理方法。当收到事件时,查询并显示被选中项的详细信息:
public void onResume() {
super.onResume();
bus.registerSticky(this);
public void onPause() {
bus.unregister(this);
super.onPause();
public void onEvent(ItemSelectedEvent event) {
Item item = MockDataSource.ITEMS.get(event.position);
titleView.setText(item.title);
dateView.setText(item.getDateStr());
bodyView.setText(item.body);
最后,在Main组件(MainActivity.java)中将所有内容集合到一起。Activity自身注册监听sticky事件,并创建与Detail组件一样的ItemSelectedEvent处理方法。当收到事件时,根据当前页面布局(layout)决定将Detail fragment加载哪个合适的容器中。
protected void onResume() {
super.onResume();
bus.registerSticky(this);
bus.postSticky(new LayoutEvent(isTwoPane()));
protected void onPause() {
bus.unregister(this);
super.onPause();
public void onEvent(ItemSelectedEvent event) {
if(isTwoPane()){
getFragmentManager().beginTransaction()
.replace(detailContainer.getId(), new ItemDetailFragment())
.commit();
getFragmentManager().beginTransaction()
.replace(listContainer.getId(), new ItemDetailFragment())
.addToBackStack(ItemDetailFragment.class.getName())
.commit();
注意,这个activity不仅监听sticky事件,还发送了另外一个sticky事件用来传递当前屏幕模式。这一事件随后会被List fragment(ItemListFragment.java)收到,并且根据条件对列表进行设置:
public void onEvent(LayoutEvent event) {
if(event.isTwoPane){
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
updateSelectedItem(activePosition);
getListView().setChoiceMode(ListView.CHOICE_MODE_NONE);
另外可以看到,没有一个组件要去实现onSaveInstanceState(Bundle bundle)以及onRestoreInstanceState(Bundle bundle)方法。取而代之的是它们只需简单地依赖于在registerSticky(this)时自动发送的缓存事件。所以,当用户选择一个项目并且在查看详细信息时,以下情况便会在配置改变时自动发生:
在onPause时,每个组件都会将自身从EventBus注销掉。
Main activity重启并在它的onResume方法里注册监听sticky事件。
缓存的ItemSelectedEvent被发送到Main activity,然后Detail fragment被加载。
Detail fragment的onResume被调用并且接收到ItemSelectedEvent,从而使得被选中项目的详细信息被显示出来。
此外,List fragment的onResume被调用并且收到ItemSelectedEvent和LayoutEvent,然后根据当前布局正确地显示被选中项目。
希望这篇文章对你能有帮助。如之前提到的,所有的示例代码都可以在这里访问到:/wongcain/EventBus-Config-Demo/
下一篇将是有关EventBus系列教程的最后一篇, 我将谈一谈在EventBus中有关跨越多线程和进程的有关内容。
全能程序员交流QQ群,聚集很多互联网精英,技术总监,架构师,项目经理!开源技术研究,欢迎业内人士,大牛及新手有志于从事IT行业人员进入!
12345678910
12345678910
1Android开发手写(29) 基于Http的LaTeX数学公式转换器345678910 上一篇:下一篇:文章评论相关解决方案 1234567891011 Copyright & &&版权所有你正在使用的浏览器版本过低,将不能正常浏览和使用知乎。快速Android开发系列通信篇之EventBu;**EventBus**是一个Android端优;作为一个消息总线,有三个主要的元素:;?Event:事件Subscriber:事件订阅;Event;**Event**可以是任意类型的对象;Subscriber;在EventBus中,使用约定来指定事件订阅者以;onEventMainThread,onEven
快速Android开发系列通信篇之EventBus
先吐槽一下博客园的MarkDown编辑器,推出的时候还很高兴博客园支持MarkDown了,试用了下发现支持不完善就没用了,这次这篇是在其他编辑器下写的,复制过来后发现。。太烂了。怎么着作为一个技术博客社区,对代码的支持应该完善一下吧,`行内代码块`不支持就算了,代码段内还不能有空行,一有空行就识别不了了。而且试着用MarkDown发了篇草稿,右边的侧边栏竟然被挤到屏幕下方了,还影响到了博客布局。。不说了。。简单修改下标题、代码直接发表。 概述及基本概念
**EventBus**是一个Android端优化的publish/subscribe消息总线,简化了应用程序内各组件间、组件与后台线程间的通信。比如请求网络,等网络返回时通过Handler或Broadcast通知UI,两个Fragment之间需要通过Listener通信,这些需求都可以通过**EventBus**实现。
作为一个消息总线,有三个主要的元素:
? Event:事件 Subscriber:事件订阅者,接收特定的事件 Publisher:事件发布者,用于通知Subscriber有事件发生
**Event**可以是任意类型的对象。
Subscriber
在EventBus中,使用约定来指定事件订阅者以简化使用。即所有事件订阅都都是以onEvent开头的函数,具体来说,函数的名字是onEvent,
onEventMainThread,onEventBackgroundThread,onEventAsync这四个,这个和ThreadMode有关,后面再说。
可以在任意线程任意位置发送事件,直接调用EventBus的`post(Object)`方法,可以自己实例化EventBus对象,但一般使用默认的单例就好了:
`EventBus.getDefault()`,根据post函数参数的类型,会自动调用订阅相应类型事件的函数。
ThreadMode
前面说了,Subscriber函数的名字只能是那4个,因为每个事件订阅函数都是和一个`ThreadMode`相关联的,ThreadMode指定了会调用的函数。有以下四个ThreadMode:
? PostThread:事件的处理在和事件的发送在相同的进程,所以事件处理
时间不应太长,不然影响事件的发送线程,而这个线程可能是UI线程。对应的函数名是onEvent。
? MainThread: 事件的处理会在UI线程中执行。事件处理时间不能太长,
这个不用说的,长了会ANR的,对应的函数名是onEventMainThread。
? BackgroundThread:事件的处理会在一个后台线程中执行,对应的函数
名是onEventBackgroundThread,虽然名字是BackgroundThread,事件处理是在后台线程,但事件处理时间还是不应该太长,因为如果发送事件的线程是后台线程,会直接执行事件,如果当前线程是UI线程,事件会被加到一个队列中,由一个线程依次处理这些事件,如果某个事件处理时间太长,会阻塞后面的事件的派发或处理。
? Async:事件处理会在单独的线程中执行,主要用于在后台线程中执行耗
时操作,每个事件会开启一个线程(有线程池),但最好限制线程的数目。 根据事件订阅都函数名称的不同,会使用不同的ThreadMode,比如果在后台线程加载了数据想在UI线程显示,订阅者只需把函数命名为onEventMainThread。
基本的使用步骤就是如下4步,点击此链接查看例子及介绍。
1. 定义事件类型:
`public class MyEvent {}`
2. 定义事件处理方法:
`public void onEventMainThread`
3. 注册订阅者:
`EventBus.getDefault().register(this)`
4. 发送事件:
`EventBus.getDefault().post(new MyEvent())` 实现
**EventBus**使用方法很简单,但用一个东西,如果不了解它的实现用起来心里总是没底,万一出问题咋办都不知道,所以还是研究一下它的实现,肯定要Read the fucking Code。其实主要是`EventBus`这一个类,在看看Code时需要了解几个概念与成员,了解了这些后实现就很好理解了。 ?
? EventType:onEvent\*函数中的参数,表示事件的类型 Subscriber:订阅源,即调用register
注册的对象,这个对象内包含
onEvent\*函数
? SubscribMethod:`Subscriber`内某一特定的onEvent\*方法,内部成
员包含一个`Method`类型的method成员表示这个onEvent\*方法,一个`ThreadMode`成员threadMode表示事件的处理线程,一个`Class&?&`类型的eventType成员表示事件的类型`EventType`。
? Subscription,表示一个订阅对象,包含订阅源`Subscriber`,订阅源中
的某一特定方法`SubscribMethod`,这个订阅的优先级`priopity`
了解了以上几个概念后就可以看`EventBus`中的几个重要成员了
// EventType -& List&Subscription&,事件到订阅对象之间的映射
private final Map&Class&?&, CopyOnWriteArrayList&Subscription&&
subscriptionsByEventT
// Subscriber -& List&EventType&,订阅源到它订阅的的所有事件类型的映射 private final Map&Object, List&Class&?&&& typesByS
// stickEvent事件,后面会看到
private final Map&Class&?&, Object& stickyE
// EventType -& List&? extends EventType&,事件到它的父事件列表的映射。即缓存一个类的所有父类
private static final Map&Class&?&, List&Class&?&&& eventTypesCache = new HashMap&Class&?&, List&Class&?&&&();
注册事件:Register
通过`EventBus.getDefault().register`方法可以向`EventBus`注册来订阅事件,`register`有很多种重载形式,但大都被标记为`Deprecated`了,所以还是不用为好,前面说了事件处理方法都是以*onEvent*开头,其实是可以通过register方法修改的,但相应的方法被废弃了,还是不要用了,就用默认的*onEvent*,除下废弃的register方法,还有以下4个**public**的`register`方法
public void register(Object subscriber) {
register(subscriber, defaultMethodName, false, 0);
public void register(Object subscriber, int priority) {
register(subscriber, defaultMethodName, false, priority);
public void registerSticky(Object subscriber) {
register(subscriber, defaultMethodName, true, 0);
三亿文库包含各类专业文献、中学教育、高等教育、生活休闲娱乐、专业论文、行业资料、12快速Android开发系列通信篇之EventBus等内容。 
 快速Android 开发系列通信篇之 EventBus 先吐槽一下博客园的 MarkDown 编辑器,推出的时候还很高兴博客园支持 MarkDown 了, 试用了下发现支持不完善就没用了,这次...  快速Android 开发系列通信篇之 EventBus 先吐槽一下博客园的 MarkDown 编辑器,推出的时候还很高兴博客园支持 MarkDown 了,试用了下发现支持不完善就没用了,这次这...  EventBus是一个Android端优化的publish/subscribe消息总线,简化了应用程序内各组件间、组件与后台线程间的通信。本视频详细了EventBus框架的核心功能包括且不仅限于:主...  19. 20. de.greenrobot.event.EventB android.app.A android.os.B android.view.V android.widget.B class private @Override ...【攻克Android (35)】EventBus事件总线分发库 - Xiangdong Lee - ITeye技术网站
博客分类:
本文围绕以下六个部分展开:
一、事件总线管理
二、EventBus
三、EventBus与BroadcastReceiver的区别
案例一
案例二:一处点击发送数据,另一处或多处注册点可以及时获取更新传输过来的数据
案例三:Activity和Service之间互相发布与接收事件
一、事件总线管理
&&&&&&& 将事件放入队列里,用于管理和分发。
&&&&&&& (1)保证应用的各个部分之间高效的通信及数据、事件分发。
&&&&&&& (2)模块间解耦:通过事件的分发,可以让各个模块间关联程序变小。
&&&&&&& 当在开发一些庞大的的项目时,模块比较多,这个时候为了避免耦合度和保证 APP 的效率,会用到 EventBus 等类似的事件总线处理模型。这样可以简化一些数据传输操作,保证APP的简洁,做到高内聚、低耦合。
二、EventBus
&&&&&&& 1. 概念
&&&&&&& EventBus是一个发布/订阅的事件总线。它可以让两个组件相互通信,但是它们之间并不相互知晓。
&&&&&&& EventBus模式,也被称为 Message Bus模式,或者 发布者/订阅者(publisher/subscriber)模式。
&&&&&&& 事件响应有更多的线程选择,EventBus 可以向不同的线程中发布事件。
&&&&&&& EventBus 支持 Sticky Event。
&&&&&&& 2. 有3个主要的元素:
&&&&&&& (1)Event:事件。
&&&&&&& Event可以是任意类型的对象。
&&&&&&& (2)Subscriber:事件订阅者,接收特定的事件。
&&&&&&& 在EventBus中,使用约定来指定事件订阅者以简化使用。即,所有事件订阅都是以onEvent开头的函数。具体来说,函数的名字是onEventMainThread,onEventPostThread,onEventBackgroundThread,onEventAsync这四个,onEvent是默认的接收数据处理的方法。这四个事件订阅函数,每个都与一个“ThreadMode”相关联,ThreadMode指定了会调用的函数。有以下4个ThreadMode:
&&&&&&& 1)PostThread:事件的处理和事件的发送在相同的进程。
&&&&&&& 事件处理时间不应太长,不然影响事件的发送线程,而这个线程可能是UI线程。对应的函数名是onEvent。
&&&&&&& 2)MainThread:事件的处理会在UI线程中执行。
&&&&&&& 事件处理时间不应太长,长了会ANR的。对应的函数名是onEventMainThread。
&&&&&&& 3)BackgroundThread:事件的处理会在一个后台线程中执行。
&&&&&&& 虽然事件处理是在后台线程,但事件处理时间还是不应该太长,因为如果发送事件的线程是后台线程,会直接执行事件。如果当前线程是UI线程,事件会被加到一个队列中,由一个线程依次处理这些事件,如果某个事件处理时间太长,会阻塞后面的事件的派发或处理。对应的函数名是onEventBackgroundThread。
&&&&&&& 4)AsyncThread:事件处理会在单独的线程中执行。
&&&&&&& 主要用于在后台线程中执行耗时操作,每个事件会开启一个线程(有线程池),但最好限制线程的数目。
&&&&&&& 根据事件订阅的函数名称的不同,会使用不同的ThreadMode。比如在后台线程加载了数据想在UI线程显示,订阅者只需把函数命名为onEventMainThread。
&&&&&&& 3. 基本用法
&&&&&&& 分 注册、订阅、发布、注销注册 等步骤。使用时需先注册、订阅,然后向订阅者发布消息数据即可。
&&&&&&& (1)注册(3个构造方法):
&&&&&&& EventBus.getDefault().register(this);
&&&&&&& EventBus.getDefault().register(new MyClass());
&&&&&&& // 注册三个参数分别是:消息订阅者(接收者),接收方法名,事件类。&&&&&&&& EventBus.getDefault().register(this,"setTextA",SetTextAEvent.class);
&&&&&&& (2)注销注册:
&&&&&&& EventBus.getDefault().unregister(this);
&&&&&&& EventBus.getDefault().unregister(new MyClass());
&&&&&&& (3)定义事件类型:
&&&&&&& public class MyEvent {}
&&&&&&& (4)订阅处理数据:
&&&&&&& public void onEvent(AnyEventType event){}:默认的接收数据处理的方法
&&&&&&& public void onEventMainThread{}
&&&&&&& onEventPostThread
&&&&&&& onEventBackgroundThread
&&&&&&& onEventAsync
&&&&&&& (5)发布:
&&&&&&& EventBus.getDefault().postSticky(new SecondActivityEvent("Message from SecondActivity"));
&&&&&&& EventBus.getDefault().post(new ChangeImgEvent(1));
三、EventBus与BroadcastReceiver的区别
&&&&&&& 1. 二者类似。
&&&&&&& 在Android中广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器)。
&&&&&&& 广播:在一个地方注册广播,在另一个地方针对action发送广播、传递数据,对应注册的地方就可以收到广播。
&&&&&&& EventBus:基于订阅/发布的模式。在需要接收数据的地方,进行注册与订阅,在需要发布数据的地方发布,则在注册的地方就可以收到了。
&&&&&&& 简单点说,就是两人约定好怎么通信,一人发布消息,另外一个约定好的人立马接收到你发的消息。EventBus就可以帮助减少做很多事,不管你在任何地方任何位置发布一个事件,接收者都能立马接收到你的消息,不用你考虑android子线程操作UI线程的问题。
&&&&&&& 2. 二者区别。
&&&&&&& (1)EventBus 有三个主要的元素:事件、订阅和发布。广播两个元素:订阅和发布,但是广播是针对整个App而言的。
&&&&&&& (2)BroadcastReceiver是组件,需要在功能清单中注册。而EventBus 不需要注册。
&&&&&&& (3)BroadcastReceiver只能做一件事情,而EventBus多事件处理比较好。
&&&&&&& (4)在不同场景中的适用性:
&&&&&&&&&&& 1)同一App内部的同一组件内的消息通信(单个或多个线程之间),实际应用中肯定是不会用到广播机制的(虽然可以用),无论是使用扩展变量作用域、基于接口的回调还是Handler-post/Handler-Message等方式,都可以直接处理此类问题,若使用广播机制,显然有些“杀鸡牛刀”的感觉。
&&&&&&&&&&& 2)同一app内部的不同组件之间的消息通信(单个进程),对于此类需求,在有些教复杂的情况下单纯的依靠基于接口的回调等方式不好处理,此时可以直接使用EventBus等,相对而言,EventBus由于是针对同一进程,用于处理此类需求非常适合,且轻松。
&&&&&&&&&&& 3)其他情形,由于涉及不同进程间的消息通信,此时根据实际业务使用广播机制会显得非常适宜。
&&&&&&& MainActivity
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1. 注册
EventBus.getDefault().register(this);
* 3. 发送数据消息事件
private void postData() {
String string = "我是消息";
EventBus.getDefault().post(string);
* 2. 接收数据消息事件
public void onEvent(String string) {
public void onEventMainThread(String string) {
public void onEventPostThread(String string) {
public void onEventBackgroundThread(String string) {
public void onEventAsync(String string) {
protected void onDestroy() {
super.onDestroy();
// 4. 取消注册
EventBus.getDefault().unregister(this);
案例二:一处点击发送数据,另一处或多处注册点可以及时获取更新传输过来的数据
&&&&&&& 1. activity_main.xml。写一个按钮和一个文本框。
&RelativeLayout xmlns:android="/apk/res/android"
xmlns:tools="/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity"&
android:id="@+id/btnSend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="发送事件"/&
android:id="@+id/tvContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/btnSend"
android:gravity="center"
android:textSize="20sp"/&
&/RelativeLayout&
&&&&&&& 2. MainActivity。声明和初始化两个控件。
private TextView tvC
private Button btnS
tvContent = (TextView) findViewById(R.id.tvContent);
btnSend = (Button) findViewById(R.id.btnSend);
&&&&&&& 3. MainActivity。onCreate()方法中注册。
EventBus.getDefault().register(this);
&&&&&&& 4. MainActivity。onDestroy()方法中取消注册。
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
&&&&&&& 5. MainActivity。通过事件监听器设置按钮的点击事件。
btnSend.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
&&&&&&& 6. 创建自定义的事件类:MyEvent。
package com.android.
* 自定义的事件类
public class MyEvent {
public String getType() {
public void setType(String type) {
this.type =
public String getContent() {
public void setContent(String content) {
this.content =
&&&&&&& 7. MainActivity。在按钮点击事件中,创建自定义事件类MyEvent的实例事件,并当点击按钮的时候,发送事件。
btnSend.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
MyEvent event = new MyEvent();
event.setType("0");
event.setContent("0内容");
// 发送数据事件
EventBus.getDefault().post(event);
&&&&&&& 8. MainActivity。通过onEvent()订阅(接收)事件。
public void onEvent(MyEvent event){
if(event.getType().equals("0")){
tvContent.setText(event.getContent());
&&&&&&& 运行效果如下:
&&&&&&& 9. MainActivity。在按钮点击事件中,将事件类型和内容改变,并当点击按钮的时候,发送事件。
btnSend.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
MyEvent event = new MyEvent();
event.setType("1");
event.setContent("1内容");
// 发送数据事件
EventBus.getDefault().post(event);
&&&&&&& 10. MainActivity。通过onEventMainThread()同样可以订阅(接收)事件。
public void onEventMainThread(MyEvent event){
if(event.getType().equals("1")){
tvContent.setText(event.getContent());
&&&&&&& 运行效果如下:
&&&&&&& 代码补充:
&&&&&&& 1. activity_main.xml
&&&&&&& 2. MainActivity
package com.android.
import android.app.A
import android.os.B
import android.view.M
import android.view.MenuI
import android.view.V
import android.widget.B
import android.widget.TextV
import de.greenrobot.event.EventB
public class MainActivity extends Activity {
private TextView tvC
private Button btnS
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvContent = (TextView) findViewById(R.id.tvContent);
btnSend = (Button) findViewById(R.id.btnSend);
btnSend.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
MyEvent event = new MyEvent();
event.setType("0");
event.setContent("0内容");
// 发送数据事件
EventBus.getDefault().post(event);
EventBus.getDefault().register(this);
* @param event
public void onEvent(MyEvent event){
if(event.getType().equals("0")){
tvContent.setText(event.getContent());
* @param event
public void onEventMainThread(MyEvent event){
if(event.getType().equals("1")){
tvContent.setText(event.getContent());
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
// -----------------------------------------------------------
public boolean onCreateOptionsMenu(Menu menu) {
// I this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return super.onOptionsItemSelected(item);
&&&&&&& 3. MyEvent
package com.android.
* 7. 自定义的事件类
public class MyEvent {
public String getType() {
public void setType(String type) {
this.type =
public String getContent() {
public void setContent(String content) {
this.content =
案例三:Activity和Service之间互相发布与接收事件
&&&&&&& 主活动有4家公司名显示,当在文本框中输入“Amazon”,点击按钮后,将新的公司名显示在主活动界面上。
&&&&&&& 1. 创建一个Service: EventService。
&&&&&&& 2. EventService。将onBind中的异常去掉,改为 返回null。
public IBinder onBind(Intent intent) {
&&&&&&& 3. activity_main.xml。一个显示的文本框,用于显示Service发布的事件;一个可编辑文本框,用于输入字符串,并发布事件到Service;一个按钮,通过点击按钮,发布事件,然后Service进行订阅。
&RelativeLayout xmlns:android="/apk/res/android"
xmlns:tools="/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity"&
android:id="@+id/tvCompany"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" /&
android:id="@+id/txtCompany"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tvCompany"
android:hint="@string/txt_company" /&
android:id="@+id/btnCompany"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/txtCompany"
android:text="@string/btn_send_company" /&
&/RelativeLayout&
&&&&&&& 4. EventService。重写onCreate()、onStartCommand()、onDestroy()方法。
&&&&&&& 5. EventService。声明一个 List 集合,用于放公司名的集合,并在onCreate()方法中创建实例(ArrayList类型)。
private List&String&
list = new ArrayList&&();
&&&&&&& 6. EventService。在onStartCommand()方法中,往List集合中添加元素(公司名)。销毁(onDestroy())的时候,集合设为null。
list.add("Google");
list.add("Facebook");
list.add("Twitter");
list.add("Apple");
&&&&&&& 8. EventService。onCreate()中注册EventBus,onDestroy()销毁时注销注册。
EventBus.getDefault().register(this);
EventBus.getDefault().unregister(this);
&&&&&&& 9. MainActivity。onCreate()中同样注册EventBus,onDestroy()销毁时同样注销注册。
&&&&&&& 10. 新建一个目录:event,用来放事件类。
&&&&&&& 11. 在event目录下,新建一个用于从 Service 发布集合数据(公司名的集合)集合事件类:ListEvent。
public class ListEvent {
private List&String&
// 含参构造方法
public ListEvent(List&String& list) {
this.list =
// getter方法(只需getter方法)
public List&String& getList() {
&&&&&&& 12. 在event目录下,新建一个用于从 Activity 发布字符串(公司名)的集合事件类:CompanyEvent。
public class CompanyEvent {
// 字符串 company
// 含参构造方法
public CompanyEvent(String company) {
// getter方法(只需getter方法)
public String getCompany() {
&&&&&&& 13. MainActivity。在按钮点击事件中,发布事件。
@OnClick(R.id.btnCompany)
public void btnCompanyClick() {
// 获得 在 txtCompany 文本框中输入的 company 字符串 的值
String company = txtCompany.getText().toString();
// Activity 发布事件 --- 将 在 txtCompany 文本框中输入的 company 字符串,
使用 CompanyEvent 发布过去
EventBus.getDefault().post(new CompanyEvent(company));
// 发布之后,将 文本框内容清空
txtCompany.setText("");
&&&&&&& 14. EventService。Service订阅事件,将Activity发布的公司名加入List集合中。然后,再将最新的公司名List集合发布出去。
* Service 订阅事件
* @param event
public void onEvent(CompanyEvent event){
// 将 事件中传过来的、在 txtCompany 文本框中输入的 company 字符串,放入 list集合中
list.add(event.getCompany());
// 再将 list集合,发布给 Activity,
// 这样,Activity订阅后,就可以在 控制台和界面上 显示最新的 list集合的值
EventBus.getDefault().postSticky(new ListEvent(list));
&&&&&&& 15. MainActivity。Activity 订阅了ListEvent事件,所以接收到了Service发布的公司名List集合的值,然后将其显示在控制台和界面的文本上。
* Activity 订阅事件
* @param event
public void onEvent(ListEvent event) {
// 从Service发布的事件中获得 参数值(list集合)
List&String& list = event.getList();
// 日志输出 list集合的值 (控制台显示 list集合的值)
Log.v(TAG, list.toString());
// 将 list集合的值 显示在 tvCompany 文本中。(界面的文本上 显示 list集合的值)
tvCompany.setText(list.toString());
&&&&&&& 代码目录结构:
&&&&&&& 补充代码:
&&&&&&& (1)EventService。
package com.android.
import android.app.S
import android.content.I
import android.os.IB
import android.util.L
import com.android.panyE
import com.android.eventbusservice.event.ListE
import java.util.ArrayL
import java.util.L
import de.greenrobot.event.EventB
public class EventService extends Service {
private static final String TAG = "MainActivity";
// 声明一个 List 集合 -- 用于放公司名的集合
private List&String&
public EventService() {
public void onCreate() {
super.onCreate();
Log.v(TAG,"Service.onCreate");
// 当前组件注册事件
// (注册事件后,一定要有 onEvent() 方法,否则报错)
EventBus.getDefault().register(this);
// 创建实例 - ArrayList类型
list = new ArrayList&&();
* 此方法系统自动调用,不写也可。可把里面的代码写入 onCreate()里面。
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v(TAG,"Service.onStartCommand");
// 往集合中添加元素
list.add("Google");
list.add("Facebook");
list.add("Twitter");
list.add("Apple");
// Service 发布事件 -- 将 list 集合,使用 ListEvent 发送过去
(ListEvent:用于从 Service 传事件到 Activity)
EventBus.getDefault().postSticky(new ListEvent(list));
// 改为:返回 START_STICKY
return START_STICKY;
public void onDestroy() {
super.onDestroy();
Log.v(TAG, "Service.onDestroy");
// 销毁的时候,取消事件
EventBus.getDefault().unregister(this);
// 销毁的时候,集合设为空
* Service 订阅事件
* @param event
public void onEvent(CompanyEvent event){
// 将 事件中传过来的、在 txtCompany 文本框中输入的 company 字符串,放入 list集合中
list.add(event.getCompany());
// 再将 list集合,发布给 Activity,
// 这样,Activity订阅后,就可以在 控制台和界面上 显示最新的 list集合的值
EventBus.getDefault().postSticky(new ListEvent(list));
public IBinder onBind(Intent intent) {
&&&&&&& (2)MainActivity。
package com.android.
import android.app.A
import android.content.I
import android.os.B
import android.util.L
import android.view.M
import android.view.MenuI
import android.widget.EditT
import android.widget.TextV
import com.android.panyE
import com.android.eventbusservice.event.ListE
import java.util.L
import butterknife.ButterK
import butterknife.InjectV
import butterknife.OnC
import de.greenrobot.event.EventB
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
@InjectView(R.id.tvCompany)
TextView tvC
@InjectView(R.id.txtCompany)
EditText txtC
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
// 在 Activity 中同样注册事件
EventBus.getDefault().register(this);
// 启动服务 -- 使用 startService 方式启动
// 启动服务后,activity与service脱钩了。
// 但是可以通过黄油刀进行联系。
startService(new Intent(this, EventService.class));
protected void onDestroy() {
super.onDestroy();
// 在 Activity 中同样注销事件
EventBus.getDefault().unregister(this);
@OnClick(R.id.btnCompany)
public void btnCompanyClick() {
// 获得 在 txtCompany 文本框中输入的 company 字符串 的值
String company = txtCompany.getText().toString();
// Activity 发布事件 --- 将 在 txtCompany 文本框中输入的 company 字符串,
使用 CompanyEvent 发布过去
EventBus.getDefault().post(new CompanyEvent(company));
// 发布之后,将 文本框内容清空
txtCompany.setText("");
* Activity 订阅事件
* @param event
public void onEvent(ListEvent event) {
// 从Service发布的事件中获得 参数值(list集合)
List&String& list = event.getList();
// 日志输出 list集合的值 (控制台显示 list集合的值)
Log.v(TAG, list.toString());
// 将 list集合的值 显示在 tvCompany 文本中。(界面的文本上 显示 list集合的值)
tvCompany.setText(list.toString());
// ---------------------------------------------------------
public boolean onCreateOptionsMenu(Menu menu) {
// I this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return super.onOptionsItemSelected(item);
整理时重点参考:
XiangdongLee
浏览: 32117 次
来自: 长沙
HTTP默认方式下,使用持久连接。 这个值得推敲
特别腻害呢
好腻害啊,
哇 受益了 太腻害

我要回帖

更多关于 家蛇 的文章

 

随机推荐