一、前言
1、好雨是一款鸿蒙系统上的,基于ActiveData的事件总线框架。好雨一词来源于“好雨知时节,当春乃发生”,好雨知道下雨的节气,正是在春天植物萌发生长的时候。好雨是一款基于ActiveData
的事件总线框架。ActiveData
知道发送数据给观察者的时候正是宿主活跃的时候,宿主销毁的时候正是移除观察者的时候。
2、在鸿蒙系统事件总线框架—好雨这篇文章中,我们介绍了好雨的用法,如果你还不熟悉好雨的用法,建议你先去看下。本文会介绍好雨的实现原理,带领大家手写好雨。
3、这里先给出源码。
二、ActiveData的用法
好雨是基于ActiveData
的,所以需要先熟悉ActiveData
的用法,ActiveData
的详解可以阅读“好雨知时节,当春乃发生”的ActiveData这篇文章。我们先来回顾下ActiveData
的用法。
创建DataObserver
对象,在onStart
方法里面创建ActiveData
对象,调用ActiveData
的setData
方法发送数据,调用DataObserver
的setLifecycle
方法来给观察者设置生命周期,调用addObserver
方法给ActiveData
添加观察者,addObserver
方法的第二个参数为false
,这就意味着,只有当宿主处在活跃状态的时候,观察者才会接收到数据。
public class MainAbility extends Ability {
private DataObserver<String> mDataObserver1 = new DataObserver<String>() {
/**
* 接收ActiveData发送过来的数据
*
* @param s
*/
@Override
public void onChanged(String s) {
LogUtils.info("yunfei", s);
}
};
private DataObserver<String> mDataObserver2 = new DataObserver<String>() {
/**
* 接收ActiveData发送过来的数据
*
* @param s
*/
@Override
public void onChanged(String s) {
LogUtils.info("yunfei", s);
}
};
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setMainRoute(MainAbilitySlice.class.getName());
// 创建ActiveData对象,泛型为string,这也就意味着,ActiveData发送一个字符串给观察者
ActiveData<String> activeData = new ActiveData<>();
// 发送数据
activeData.setData("更新页面");
// 给观察者设置生命周期,直接调用宿主的getLifecycle()方法
mDataObserver1.setLifecycle(getLifecycle());
mDataObserver2.setLifecycle(getLifecycle());
// 添加观察者,第二个参数false,这就意味着,只有当宿主处在活跃状态的时候,activeData才把数据发送给观察者
activeData.addObserver(mDataObserver1, false);
activeData.addObserver(mDataObserver2, false);
LogUtils.info("yunfei", "onStart");
}
@Override
protected void onActive() {
super.onActive();
LogUtils.info("yunfei", "onActive");
}
}
在上面的代码中,创建了两个观察者,ActiveData
只发送了一次消息,但两个观察者都收到了同一个消息。这在一定程度上会给我们带来麻烦。比如,发送登录事件,登录完成后,又来了一个观察者,新的观察者也能收到登录事件,此时又会进行登录。接下来就来手写好雨框架,并且解决这个问题。
三、手写好雨框架
3、1 ActiveDataBus类
3、1、1 创建ActiveDataBus
,继承ActiveData
。在ActiveDataBus
里面有个mVersion
属性,每当发送消息时,该属性的值加一。该类会重写ActivaData
的setData
方法,并且提供注册观察者的方法。下面具体讲解ActivaDataBus
里面的方法。
public class ActiveDataBus<T> extends ActiveData<T> {
/**
* 事件名称
*/
private final String eventName;
/**
* 发送的消息
*/
public T value;
// 发送消息时,该属性的值加一
public int mVersion;
public ActiveDataBus(String eventName) {
this.eventName = eventName;
}
/**
* 发送数据
*
* @param value 数据
*/
@Override
public void setData(T value) {
// 版本加一
mVersion++;
this.value = value;
super.setData(value);
}
/**
* 注册观察者,监听普通消息,只有当宿主活跃时,观察者才会接收到消息。
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
*/
public void observe(ILifecycle iLifecycle, DataObserver<T> observer) {
addObserver(iLifecycle, observer, false, false);
}
/**
* 注册观察者,监听普通消息,在任何生命周期状态下都将消息发送给观察者,即便宿主不活跃,观察者也会接收到消息。
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
*/
public void observeAlways(ILifecycle iLifecycle, DataObserver<T> observer) {
addObserver(iLifecycle, observer, false, true);
}
/**
* 注册观察者,监听粘性消息,只有当宿主活跃时,观察者才会接收到消息。
* 粘性消息指的是消息先发送,后注册的观察者也能接收到之前发送的信息。
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
*/
public void observeSticky(ILifecycle iLifecycle, DataObserver<T> observer) {
addObserver(iLifecycle, observer, true, false);
}
/**
* 注册观察者,监听粘性消息,在任何生命周期状态下都将消息发送给观察者,即便宿主不活跃,观察者也会接收到消息。
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
*/
public void observeStickyAlways(ILifecycle iLifecycle, DataObserver<T> observer) {
addObserver(iLifecycle, observer, true, true);
}
/**
* 添加观察者
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
* @param sticky 观察者是否接收粘性消息
* @param always false表示当宿主活跃的时候才将消息发生给观察者,
* true表示在任何生命周期状态下都将消息发送给观察者,即便宿主不活跃,观察者也会接收到消息。
*/
public void addObserver(ILifecycle iLifecycle, DataObserver<T> observer, boolean sticky, boolean always) {
Lifecycle lifecycle = iLifecycle.getLifecycle();
ActiveDataObserver<T> activeDataObserver = new ActiveDataObserver<>(this, sticky, observer);
// 给观察者设置生命周期
activeDataObserver.setLifecycle(lifecycle);
super.addObserver(activeDataObserver, always);
}
}
3、1、2 重写setData
方法,每当调用setData
方法时,将mVersion
属性加一,然后调用ActiveData
的setData
方法。
/**
* 发送数据
*
* @param value 数据
*/
@Override
public void setData(T value) {
// 版本加一
mVersion++;
this.value = value;
super.setData(value);
}
3、1、3 注册观察者的方法。
observe
方法监听普通消息,只有当宿主活跃时,观察者才会接收到消息。
observeAlways
方法监听普通消息,在任何生命周期状态下都将消息发送给观察者,即便宿主不活跃,观察者也会接收到消息。
observeSticky
方法监听粘性消息,只有当宿主活跃时,观察者才会接收到消息。
observeStickyAlways
方法监听粘性消息,在任何生命周期状态下都将消息发送给观察者,即便宿主不活跃,观察者也会接收到消息。
/**
* 注册观察者,监听普通消息,只有当宿主活跃时,观察者才会接收到消息。
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
*/
public void observe(ILifecycle iLifecycle, DataObserver<T> observer) {
addObserver(iLifecycle, observer, false, false);
}
/**
* 注册观察者,监听普通消息,在任何生命周期状态下都将消息发送给观察者,即便宿主不活跃,观察者也会接收到消息。
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
*/
public void observeAlways(ILifecycle iLifecycle, DataObserver<T> observer) {
addObserver(iLifecycle, observer, false, true);
}
/**
* 注册观察者,监听粘性消息,只有当宿主活跃时,观察者才会接收到消息。
* 粘性消息指的是消息先发送,后注册的观察者也能接收到之前发送的信息。
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
*/
public void observeSticky(ILifecycle iLifecycle, DataObserver<T> observer) {
addObserver(iLifecycle, observer, true, false);
}
/**
* 注册观察者,监听粘性消息,在任何生命周期状态下都将消息发送给观察者,即便宿主不活跃,观察者也会接收到消息。
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
*/
public void observeStickyAlways(ILifecycle iLifecycle, DataObserver<T> observer) {
addObserver(iLifecycle, observer, true, true);
}
3、1、4 上面所有的注册观察者的方法都会调用到addObserver
方法。先创建ActiveDataObserver
对象,将调用者传递过来的观察者对象包装成ActiveDataObserver
对象,然后设置生命周期,因为最终还是利用ActiveData
来添加观察者,所以需要调用ActivaData
的addObserver
方法来添加观察者。
/**
* 添加观察者
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
* @param sticky 观察者是否接收粘性消息
* @param always false表示当宿主活跃的时候才将消息发生给观察者,
* true表示在任何生命周期状态下都将消息发送给观察者,即便宿主不活跃,观察者也会接收到消息。
*/
public void addObserver(ILifecycle iLifecycle, DataObserver<T> observer, boolean sticky, boolean always) {
Lifecycle lifecycle = iLifecycle.getLifecycle();
// 将调用者传递过来的观察者对象包装成ActiveDataObserver对象
ActiveDataObserver<T> activeDataObserver = new ActiveDataObserver<>(this, sticky, observer);
// 给观察者设置生命周期
activeDataObserver.setLifecycle(lifecycle);
super.addObserver(activeDataObserver, always);
}
3、2 ActiveDataObserver类
3、2、1 在上面的代码中,我们将调用者传递过来的观察者对象包装成ActiveDataObserver对象。ActiveDataObserver
继承了DataObserver
,ActiveDataObserver
也是观察者。当有消息过来时,就会回调ActiveDataObserver
的onChange
方法。这样我们就拥有了主动权,从而判断要不要将消息分发给调用者传递过来的观察者。每个观察者都有lastVersion
属性,该属性默认跟ActiveData的mVersion属性对齐。
3、2、2 在onChange
方法里面,如果先发送消息,那么mActiveDataBus.mVersion属性就会加一,然后注册观察者,此时就会在构造方法里面将lastVersion属性跟ActiveData的mVersion对齐。此时lastVersion >= mActiveDataBus.mVersion
等式成立。如果lastVersion >= mActiveDataBus.mVersion
,说明是粘性消息,也就是先发送了消息,后注册观察者。在这种情况下,正常是不需要将消息分发给观察者的。但是,如果观察者监听粘性事件,此时仍然要消息分发给观察者。如果lastVersion < mActiveDataBus.mVersion
,则需要将消息发送给观察者。
public class ActiveDataObserver<T> extends DataObserver<T> {
private final ActiveDataBus<T> mActiveDataBus;
/**
* 调用者传递过来的观察者
*/
private final DataObserver<T> observer;
private int lastVersion;
/**
* 观察者是否接收粘性消息
*/
private final boolean sticky;
public ActiveDataObserver(ActiveDataBus<T> activeDataBus, boolean sticky, DataObserver<T> observer) {
this.mActiveDataBus = activeDataBus;
this.observer = observer;
// 观察者的lastVersion属性跟ActiveData的mVersion对齐
lastVersion = activeDataBus.mVersion;
this.sticky = sticky;
}
@Override
public void onChanged(T t) {
/*
* 如果先发送消息,那么mActiveDataBus.mVersion属性就会加一,然后注册观察者,
* 此时就会在构造方法里面将lastVersion属性跟ActiveData的mVersion对齐,
* 此时lastVersion >= mActiveDataBus.mVersion等式成立。
* 如果lastVersion >= mActiveDataBus.mVersion,说明是粘性消息,也就是先发送了消息,后注册观察者,
* 在这种情况下,正常是不需要将消息分发给观察者的,
* 但是,如果观察者监听粘性事件,此时仍然要消息分发给观察者。
*/
if (lastVersion >= mActiveDataBus.mVersion) {
// 观察者监听粘性事件,此时仍然要消息分发给观察者
if (sticky && mActiveDataBus.value != null) {
// 观察者监听粘性事件,此时仍然要消息分发给观察者
observer.onChanged(mActiveDataBus.value);
}
return;
}
lastVersion = mActiveDataBus.mVersion;
// 需要将消息发送给观察者
observer.onChanged(t);
}
}
3、3 Observable接口
在上面的代码中,我们创建ActiveDataBus
,继承ActiveData
。由于我们并不想将ActiveData
里面的方法暴露给调用者。所以我们创建一个接口Observable
,在该接口里面提供方法给外界调用。主要是提供发送消息和注册观察者的方法。
public interface Observable<T> {
/**
* 发送消息
*
* @param value 消息
*/
void post(T value);
/**
* 延迟发送消息,当延迟时间到了后,只有宿主处在开始状态或者活跃状态时,才发送消息
*
* @param lifecycle 宿主的生命周期
* @param value 消息
* @param delay 延迟时间
*/
void postDelay(ILifecycle lifecycle, T value, long delay);
/**
* 注册观察者,监听普通消息,只有当宿主活跃时,观察者才会接收到数据。
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
*/
void observe(ILifecycle iLifecycle, DataObserver<T> observer);
/**
* 注册观察者,监听普通消息,在任何生命周期状态下都将消息发送给观察者,即便宿主不活跃,观察者也会接收到消息。
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
*/
void observeAlways(ILifecycle iLifecycle, DataObserver<T> observer);
/**
* 注册观察者,监听粘性消息,只有当宿主活跃时,观察者才会接收到数据。
* 粘性消息指的是消息先发送,后注册的观察者也能接收到之前发送的信息。
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
*/
void observeSticky(ILifecycle iLifecycle, DataObserver<T> observer);
/**
* 注册观察者,监听粘性消息,在任何生命周期状态下都将消息发送给观察者,即便宿主不活跃,观察者也会接收到消息。
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
*/
void observeStickyAlways(ILifecycle iLifecycle, DataObserver<T> observer);
}
3、4 LiveData类
LiveData
是个委托类,它实现了Observable
接口。为了不让外界直接调用ActiveData
里面的方法,创建一个委托类,在委托类里面调用ActiveData
里面的方法。LiveData
里面持有ActiveDataBus
对象,当调用LiveData
里面的方法都会调用到ActiveDataBus
里面的方法。发送消息和注册观察者都是在主线程中进行,如果当前是主线程,则直接进行发送消息或者注册观察者。如果当时不是主线程,则会使用EventHandler
切换到主线程进行发送消息或者注册观察者。
public class LiveData<T> implements Observable<T> {
private String eventName;
private final ActiveDataBus<T> mActiveDataBus;
private final EventHandler mMainHandler = new EventHandler(EventRunner.getMainEventRunner());
public LiveData(String eventName) {
this.eventName = eventName;
mActiveDataBus = new ActiveDataBus<>(eventName);
}
/**
* 发送消息
*
* @param value 消息
*/
@Override
public void post(T value) {
if (ThreadUtils.isMainThread()) {
mActiveDataBus.setData(value);
} else {
mMainHandler.postTask(new Runnable() {
@Override
public void run() {
mActiveDataBus.setData(value);
}
});
}
}
/**
* 延迟发送消息,当延迟时间到了后,只有宿主处在开始状态或者活跃状态时,才发送消息
*
* @param lifecycle 宿主的生命周期
* @param value 消息
* @param delay 延迟时间
*/
@Override
public void postDelay(ILifecycle lifecycle, T value, long delay) {
Utils.checkNotNull(lifecycle, "lifecycle must not be null");
mMainHandler.postTask(new PostLifecycleValue(value, lifecycle), delay);
}
/**
* 注册观察者,监听普通消息,只有当宿主活跃时,才将消息发送给观察者。
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
*/
@Override
public void observe(ILifecycle iLifecycle, DataObserver<T> observer) {
if (ThreadUtils.isMainThread()) {
mActiveDataBus.observe(iLifecycle, observer);
} else {
mMainHandler.postTask(new Runnable() {
@Override
public void run() {
mActiveDataBus.observe(iLifecycle, observer);
}
});
}
}
/**
* 注册观察者,监听普通消息,在任何生命周期状态下都将消息发送给观察者,即便宿主不活跃,也会将消息发送给观察者。
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
*/
@Override
public void observeAlways(ILifecycle iLifecycle, DataObserver<T> observer) {
if (ThreadUtils.isMainThread()) {
mActiveDataBus.observeAlways(iLifecycle, observer);
} else {
mMainHandler.postTask(new Runnable() {
@Override
public void run() {
mActiveDataBus.observeAlways(iLifecycle, observer);
}
});
}
}
/**
* 注册观察者,监听粘性消息,只有当宿主活跃时,才将消息发送给观察者。
* 粘性消息指的是消息先发送,后注册的观察者也能接收到之前发送的信息。
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
*/
@Override
public void observeSticky(ILifecycle iLifecycle, DataObserver<T> observer) {
if (ThreadUtils.isMainThread()) {
mActiveDataBus.observeSticky(iLifecycle, observer);
} else {
mMainHandler.postTask(new Runnable() {
@Override
public void run() {
mActiveDataBus.observeSticky(iLifecycle, observer);
}
});
}
}
/**
* 注册观察者,监听粘性消息,在任何生命周期状态下都将消息发送给观察者,即便宿主不活跃,也会将消息发送给观察者。
*
* @param iLifecycle 宿主的生命周期
* @param observer 观察者
*/
@Override
public void observeStickyAlways(ILifecycle iLifecycle, DataObserver<T> observer) {
if (ThreadUtils.isMainThread()) {
mActiveDataBus.observeStickyAlways(iLifecycle, observer);
} else {
mMainHandler.postTask(new Runnable() {
@Override
public void run() {
mActiveDataBus.observeStickyAlways(iLifecycle, observer);
}
});
}
}
private class PostLifecycleValue implements Runnable {
private final Object value;
private final Lifecycle mLifecycle;
public PostLifecycleValue(Object value, ILifecycle lifecycle) {
this.value = value;
Utils.checkNotNull(lifecycle, "lifecycle must not be mull");
mLifecycle = lifecycle.getLifecycle();
}
@Override
public void run() {
if (mLifecycle != null) {
if (mLifecycle.getLifecycleState() == Lifecycle.Event.ON_START
|| mLifecycle.getLifecycleState() == Lifecycle.Event.ON_ACTIVE) {
// 当宿主处在开始状态或者活跃状态时,才发送消息
post((T) value);
}
}
}
}
}
3、5 HaoYu类
最后创建HaoYu
类,很多时候需要跨页面发送消息,所以HaoYu
对象必须是一个单例。这里使用静态内部类来实现单例。
with
方法用来获取被观察者对象,被观察者对象保存在ConcurrentHashMap
,首先根据事件名称从ConcurrentHashMap
里面查找被观察者对象,如果能查找到则直接返回,否则创建被观察者对象,并将被观察者对象保存到ConcurrentHashMap
。
需要注意的是,with
方法的第二个参数是Class
对象,为什么需要传递Class
对象呢?这是因为with
方法是泛型方法,为了显示的确定泛型的类型,这里需要调用者传递Class
对象,Class
对象就是用来确定泛型的类型。如果不传递Class
对象,那么泛型就是Object
,Object
并不是我们想要的类型。当我们在发送消息的时候,可以调用一个参数的with
方法,此时可以不确切的知道具体的泛型。而在注册观察者的时候,一定要调用两个参数的with
方法,因为此时需要显示的确定泛型的类型了。
public class HaoYu {
/**
* 保存被观察者
*/
private final ConcurrentHashMap<String, Observable<Object>> eventMap = new ConcurrentHashMap<>();
/**
* 使用静态内部类来实现单例模式
*
* @return HaoYu对象
*/
public static HaoYu get() {
return HaoYuHolder.mInstance;
}
private static final class HaoYuHolder {
private static final HaoYu mInstance = new HaoYu();
}
/**
* 获取被观察者对象
*
* @param eventName 事件的名称
* @param <T> 泛型的类型
* @return 被观察者对象
*/
public <T> Observable<T> with(String eventName) {
return (Observable<T>) with(eventName, Object.class);
}
/**
* 获取被观察者对象
*
* @param eventName 事件的名称
* @param type 指定泛型的类型
* @param <T> 指定泛型的类型
* @return 被观察者对象
*/
public <T> Observable<T> with(String eventName, Class<T> type) {
if (!eventMap.containsKey(eventName)) {
eventMap.put(eventName, new LiveData<>(eventName));
}
return (Observable<T>) eventMap.get(eventName);
}
}
至此,好雨框架写完了。可以看到,代码并不难,大家可以将源码下载下来,结合注释,相信大家可以理解好雨框架的原理。
四、总结
本文介绍了好雨框架的实现原理,好雨框架是基于ActiveData
实现的,并且带领大家手写了好雨框架。
- 因为需要跨页面发送数据,所以创建了一个单例的
HaoYu
对象。 - 为了不每次创建被观察者对象,使用
map
来保存被观察者对象。 - 为了不将
ActiveData
的方法暴露给外界,创建了一个LiveData
,LiveData
里面持有ActiveData
对象。当调用LiveData
里面的方法都会调用到ActiveData
里面的方法。 - 为了解决
ActiveData
存在的问题,创建了一个子类继承ActiveData
。
网友评论