近来在看平凡的世界,一发不可收拾,非常震撼心灵,心里面的那种触动我真的表达不清楚。已经很久没有看到这么好看的电视剧了。如果你还没看过,我推荐大家可以去看一看。
前段时间有人问我,fragment 怎么与 activity 通信?同级下的 fragment 之间的通信?
对于这个问题有很多方案,我简单的说几种,可能还有更好的方案。
宿主 onAttach 方法获取到 activity 实例,有了实例就是调用方法的问题了。注意不同的 fragment 之间需要强转。
接口
广播 (有点大题小用了)
handler
EventBus,RxBus,Otto
五种方案各有优缺点,在项目当中根据具体情况灵活应用。这里主要讲解 EventBus 在项目中的使用,虽然 EventBus 可以很方便的实现模块与模块之间的通信,如果频繁的使用可能导致代码错乱。这点对于初学者尤为重要。下面一起来看看 EventBus 一些常用的使用方法。
什么是EventBus
EventBus是一个 发布/订阅 模式的消息总线库,它简化了应用程序内各组件间、组件与后台线程间的通信,解耦了事件的发送者和接收者,避免了复杂的、易于出错的依赖及生命周期问题,可以使我们的代码更加简洁、健壮。EventBus 用于各组件通信,那么用于 fragment 之间的通信就非常合适了。
相关文章:
EventBus的基本使用
项目依赖
gradle依赖:
在 app
的 build.gradle
文件下:
dependencies {
compile 'org.greenrobot:eventbus:3.0.0'
}
接着来撸一撸 EventBus 的使用步骤:
- 1、 定义事件
- 2、 订阅
- 3、 发布事件
1、定义事件
MessageEvent 为例:
public class MessageEvent {
public String message;
public MessageEvent(String message) {
this.message = message;
}
}
订阅
声明订阅方法,并且指定线程模式(默认主线程)。
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(this,"你好EventBus"+event.message,Toast.LENGTH_SHORT).show();
};
注意 @Subscribe annotation
是不可缺少的,onMessageEvent
方法名可以随意命名。
在 activity
或 fragment
注册和注销 EventBus
:
onCreate
注册:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
}
onStart
注册:
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
onDestroy
注销:
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
发布事件
最后即是事件源发布事件。我们可以在代码的任何位置发布事件,当前所有事件类型与发布的事件类型匹配的订阅者都将收到它。其实内部是以 map
来存储事件,map
的键就是事件类名(这里就是MessageEvent
作为键值),在发布相同事件源的时候避免多次处理。
EventBus.getDefault().post(new MessageEvent(""));
下面来看一个简单的案例(通过点击按钮来发步事件源):
public void click_event(View view) {
EventBus.getDefault().post(new MessageEvent("鸡年大吉"));
}
效果图一览:
源码我会在文章的最后给出。
Sticky事件
Sticky
事件被我称之为粘性事件,功能类似sticky broadcast
(粘性广播)。就是某些事件携带的信息在事件被发布之后依然有价值。比如,当前 activity
发布了事件源,新启的 activity
对该事件进行订阅,同样能够处理。
发布粘性事件:
EventBus.getDefault().postSticky(new MessageEvent("大吉大利"));
处理粘性事件:
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(this, "接收A发来的消息" + event.message, Toast.LENGTH_SHORT).show();
}
注意 sticky
成员设置为 true
,默认为 false
。
运行效果图:
源码会在文章最后附上
最新的sticky
事件会在注册时立即自动地被传递给匹配的订阅者。但有时手动地去检查sticky
事件可能会更方便一些。有时也可能需要移除(消费)sticky
事件以便于它不会再被传递。
移除sticky
事件:
MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
if (stickyEvent != null) {
EventBus.getDefault().removeStickyEvent(stickyEvent);
}
查看源码我们知道removeStickyEvent
方法是重载的,当传递class
时,它将返回持有的之前的sticky
事件。也可以使用如下变体进行处理:
MessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);
if (stickyEvent != null) {
//handler
}
优先级
我们可以通过优先级来改变事件传递的顺序。
@Subscribe(priority = 1)
public void onEvent(MessageEvent event) {
}
在相同的传递线程内(ThreadMode),优先级越高的订阅者越先接收到事件。默认优先级为0。在不同线程(ThreadMode)中优先级并不会影响事件的传递顺序。
取消事件
有时我们需要取消事件的传递:
@Subscribe()
public void onMessageEvent(MessageEvent event) {
//处理事件...
//取消事件
EventBus.getDefault().cancelEventDelivery(event) ;
}
所有后续的事件传递将被取消,后面的订阅者将无法接收到事件。cancelEventDelivery
方法只接收(Object event)
参数,那么我们只能在订阅者的事件处理方法中调用。
传递线程
事件可以在不同于抛出事件的线程中传递。一个很常见的例子,获取网络数据更新UI
。网络,耗时的操作必然是异步操作,更新 UI
则在 UI
线程操作。
EventBus
的传递线程类型有四类:
- ThreadMode.POSTING(默认)
- ThreadMode.MAIN (主线程)
- ThreadMode.BACKGROUND (后台线程)
- ThreadMode.ASYNC (异步线程)
ThreadMode.POSTING
默认方式,订阅者将在与抛出事件相同的线程中被调用。事件传递是同步完成的,事件传递完成时,所有的订阅者将已经被调用了一次。这个ThreadMode
意味着最小的开销,因为它完全避免了线程的切换。鉴于以上的特点,那么可以用于已知耗时非常短的简单的不需要请求主线程的任务,可以采用该模式。使用这个模式的事件处理器应该迅速返回以避免阻塞发布事件的线程,而后者可能是主线程。比如:
@Subscribe(threadMode = ThreadMode.POSTING)
public void onMessage(MessageEvent event) {
//handler事件
Toast.makeText(this, "你好EventBus" + event.message, Toast.LENGTH_SHORT).show();
}
ThreadMode.MAIN
订阅者将在主线程(UI线程)中被调用。如果发布事件的线程是主线程,事件处理器方法将会直接被调用。事件处理器使用这个模式必须快速地返回以避免阻塞主线程。
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(MessageEvent event) {
//处理事件
}
ThreadMode.BACKGROUND
订阅者将在一个后台线程中被调用。如果发布事件的线程不是主线程,事件处理器方法将在该线程中被调用;反之,EventBus
使用一个单独的后台线程,它将顺序地传递它所有的事件。使用该模式的事件处理器应该尝试快速返回以避免阻塞后台线程。
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessage(MessageEvent event) {
//handler事件
}
ThreadMode.ASYNC
订阅者将在另外一个线程中被调用。这里的另外一个线程不等同于发布事件的线程和UI
线程。用于处理比较耗时的操作,如访问网络,数据库操作。
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessage(MessageEvent event) {
//handler事件
}
EventBus
原理这里就不在深入,EventBus
真的非常棒,值得你拥有。