源码版本:JeremyLiao / LiveEventBus(master 分支) 核心文件:
com.jeremyliao.liveeventbus.core.LiveEventBusCorecom.jeremyliao.liveeventbus.core.Observableandroid.arch.lifecycle.ExternalLiveDatacom.jeremyliao.liveeventbus.core.Config
1. 从一个典型场景说起
Activity A 登录成功后需要通知 Activity B 刷新用户头像,常规做法是:
startActivityForResult/onActivityResult层层回调;- 或者在
Application里挂一个全局监听器,手动管理注册与反注册。
LiveEventBus 的思路是:用一把"钥匙"(字符串 key)把发送端和接收端串起来 ,底层交给 LiveData 做生命周期感知的消息分发。于是上面的需求可以写成:
csharp
// Activity A 登录成功后发送
LiveEventBus.get("user_login")
.post(new UserInfo("张三"));
// Activity B 订阅
LiveEventBus.get("user_login", UserInfo.class)
.observe(this, userInfo -> {
// 刷新头像
});
整个 App 里所有 Activity 只要持有同一个 key,就能像订阅同一个电台一样收发消息,而且不用手动解绑------这是 LiveData 自带的能力。
2. 核心角色一览
| 角色 | 职责 | 关键源码位置 |
|---|---|---|
LiveEventBusCore |
单例总线,持有所有 LiveEvent |
core/LiveEventBusCore.java |
LiveEvent |
对应一个 key 的消息通道,内部封装 LifecycleLiveData |
LiveEventBusCore 的非静态内部类 |
LifecycleLiveData |
继承自 ExternalLiveData,决定观察者在哪个生命周期状态算"激活" |
LiveEventBusCore 的内部类 |
ExternalLiveData |
对官方 LiveData 的扩展,开放 mVersion、自定义 observerActiveLevel |
android/arch/lifecycle/ExternalLiveData.java |
ObserverWrapper |
装饰器,控制"非粘性消息"第一次回调是否被吞掉 | LiveEventBusCore 的内部类 |
Observable |
对外接口,定义 post / observe / observeSticky 等方法 |
core/Observable.java |
Config |
全局/单 key 配置入口 | core/Config.java |
一句话总结:LiveEventBusCore 是车站,LiveEvent 是某条线路的调度室,LifecycleLiveData 是这条线路上的广播喇叭。
3. 单例与 key 路由
vbnet
public final class LiveEventBusCore {
private static class SingletonHolder {
private static final LiveEventBusCore DEFAULT_BUS = new LiveEventBusCore();
}
public static LiveEventBusCore get() {
return SingletonHolder.DEFAULT_BUS;
}
private final Map<String, LiveEvent<Object>> bus;
private LiveEventBusCore() {
bus = new HashMap<>();
// ...
}
public synchronized <T> Observable<T> with(String key, Class<T> type) {
if (!bus.containsKey(key)) {
bus.put(key, new LiveEvent<>(key));
}
return (Observable<T>) bus.get(key);
}
}
- 采用静态内部类 实现懒加载单例,线程安全且无需
synchronized锁整个方法。 with(key, type)保证同一个 key 全局只有一份LiveEvent,这是跨 Activity 能收到同一条消息的根本。- 泛型
Class<T>主要给调用端做类型提示,底层LiveEvent实际以Object存取。
4. 发送一条消息到底发生了什么
LiveEvent 里的 post 方法:
typescript
@Override
public void post(T value) {
if (ThreadUtils.isMainThread()) {
postInternal(value);
} else {
mainHandler.post(new PostValueTask(value));
}
}
@MainThread
private void postInternal(T value) {
logger.log(Level.INFO, "post: " + value + " with key: " + key);
liveData.setValue(value);
}
流程很简单:
- 无论在子线程还是主线程,最终都会切到主线程执行
setValue。 liveData.setValue(value)会触发 LiveData 自身的分发逻辑:遍历mObservers,把消息派给当前处于激活状态的观察者。
4.1 为什么最终一定要回到主线程
官方 LiveData.setValue 会检查线程:
typescript
// LiveData.java
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
所以 LiveEventBus 在框架层先把消息 post 到 mainHandler,避免调用方自己处理线程切换。
5. 不同 Activity 为什么能收到同一条消息
关键在于 liveData 是进程内单例的。当 Activity B 调用:
kotlin
LiveEventBus.get("user_login", UserInfo.class).observe(this, ...);
实际上拿到的是 LiveEventBusCore.bus.get("user_login") 里的同一个 LiveEvent 对象,同一个 LifecycleLiveData。
因此 Activity A 调用 post 修改了这个 LiveData 的值后,所有绑定到该 key 且处于激活状态的 Activity/Fragment 都会收到回调。
5.1 生命周期是怎么被"感知"的
核心类 ExternalLiveData:
scala
public class ExternalLiveData<T> extends MutableLiveData<T> {
public static final int START_VERSION = LiveData.START_VERSION;
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return;
}
try {
// 用自定义的 ExternalLifecycleBoundObserver 替代官方的 LifecycleBoundObserver
LifecycleBoundObserver wrapper = new ExternalLifecycleBoundObserver(owner, observer);
LifecycleBoundObserver existing =
(LifecycleBoundObserver) callMethodPutIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException(
"Cannot add the same observer with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
} catch (Exception e) {
e.printStackTrace();
}
}
protected Lifecycle.State observerActiveLevel() {
return CREATED;
}
class ExternalLifecycleBoundObserver extends LifecycleBoundObserver {
ExternalLifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
super(owner, observer);
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(observerActiveLevel());
}
}
}
官方 LiveData 判断观察者是否激活,用的是 Lifecycle.State.STARTED,即 Activity 必须处于 onStart 之后才会收到消息。
LiveEventBus 通过反射把观察者包装成自己的 ExternalLifecycleBoundObserver,并重写 shouldBeActive():
scss
return mOwner.getLifecycle().getCurrentState().isAtLeast(observerActiveLevel());
默认 observerActiveLevel() 返回 CREATED,也就是说只要 Activity 没有被销毁,就能收到消息。
5.2 可配置:让后台 Activity 收不到实时消息
在 Application.onCreate 中:
scss
LiveEventBus.get()
.config()
.lifecycleObserverAlwaysActive(false);
此时 LifecycleLiveData 的 observerActiveLevel() 返回 STARTED:
typescript
@Override
protected Lifecycle.State observerActiveLevel() {
return lifecycleObserverAlwaysActive() ? Lifecycle.State.CREATED : Lifecycle.State.STARTED;
}
这意味着:
true(默认):Activity 在onCreate ~ onDestroy全周期实时收消息,即使当前在后台。false:只有onStart ~ onStop之间实时收消息;后台时暂存,回到前台再补发最近一条。
6. 非粘性消息是怎么实现的
LiveData 自带"粘性":新注册的观察者会立即收到当前已存在的值。LiveEventBus 的 observe 需要避免这种行为,于是引入了 ObserverWrapper:
less
private class ObserverWrapper<T> implements Observer<T> {
@NonNull
private final Observer<T> observer;
private boolean preventNextEvent = false;
ObserverWrapper(@NonNull Observer<T> observer) {
this.observer = observer;
}
@Override
public void onChanged(@Nullable T t) {
if (preventNextEvent) {
preventNextEvent = false;
return;
}
observer.onChanged(t);
}
}
注册非粘性观察者时:
less
@MainThread
private void observeInternal(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
ObserverWrapper<T> observerWrapper = new ObserverWrapper<>(observer);
observerWrapper.preventNextEvent = liveData.getVersion() > ExternalLiveData.START_VERSION;
liveData.observe(owner, observerWrapper);
}
START_VERSION是 LiveData 初始版本号,通常为-1。- 如果
liveData.getVersion() > START_VERSION,说明这条LiveData之前已经setValue过。 - 此时把
preventNextEvent置为true,观察者注册后第一次onChanged会被拦截,从而避免收到"历史消息"。 - 后续再有新消息,
preventNextEvent已经重置为false,正常回调。
6.1 粘性订阅
less
@Override
public void observeSticky(@NonNull final LifecycleOwner owner,
@NonNull final Observer<T> observer) {
// ... 切到主线程
observeStickyInternal(owner, observer);
}
@MainThread
private void observeStickyInternal(@NonNull LifecycleOwner owner,
@NonNull Observer<T> observer) {
ObserverWrapper<T> observerWrapper = new ObserverWrapper<>(observer);
liveData.observe(owner, observerWrapper);
}
observeSticky 没有设置 preventNextEvent,因此会保留 LiveData 的默认粘性行为:
- 如果注册时已经有值,立即回调一次;
- 之后有新值,继续回调。
7. 完整流程串讲
假设当前 App 有两个 Activity:A 和 B。
csharp
1. App 启动,LiveEventBusCore 单例初始化,bus = {}。
2. Activity B 在 onCreate 中注册:
LiveEventBus.get("login_ok", UserInfo.class).observe(this, observer);
→ LiveEventBusCore.with 创建 key="login_ok" 的 LiveEvent
→ LifecycleLiveData 诞生
→ observer 被包成 ObserverWrapper,并设置 preventNextEvent
→ ExternalLiveData.observe 把 wrapper 注册到 Activity B 的 Lifecycle
3. Activity A 登录成功后调用:
LiveEventBus.get("login_ok").post(userInfo);
→ 切到主线程
→ liveData.setValue(userInfo)
→ LiveData 遍历 mObservers,发现 Activity B 的 wrapper 处于激活状态
→ wrapper.onChanged(userInfo)
→ 由于 preventNextEvent 已重置,调用业务 observer.onChanged(userInfo)
4. Activity B 被销毁,Lifecycle 自动把 wrapper 移除,无需手动 unregister。
8. 跨进程 / 跨 App 通讯和 Activity 通讯的区别
LiveEventBus 还提供:
postAcrossProcess:App 内跨进程;postAcrossApp:跨 App;broadcast:底层走sendBroadcast+LebIpcReceiver。
但在同一个进程里的不同 Activity 之间通讯时,走的还是普通的 post → setValue,不需要广播。广播方案是为了解决多进程/多 App 场景:
typescript
@Override
public void postAcrossProcess(T value) {
broadcast(value, false, true); // onlyInApp = true
}
@Override
public void postAcrossApp(T value) {
broadcast(value, false, false); // 全局
}
如果项目不是多进程架构,不需要为了跨 Activity 通讯而调用 postAcrossProcess,否则既浪费 IPC 开销,又增加序列化限制。
9. 容易被忽略的细节
9.1 autoClear:没有观察者时是否清掉通道
less
@Override
public void removeObserver(@NonNull Observer<T> observer) {
super.removeObserver(observer);
if (autoClear() && !liveData.hasObservers()) {
LiveEventBusCore.get().bus.remove(key);
}
}
默认 autoClear = false。开启后,当某个 key 下没有任何观察者时,会从 bus 中移除,避免空 LiveEvent 长期驻留。
9.2 子线程发送
post 内部已经做了线程切换,业务方可以安全地在子线程调用。如果想保证消息顺序,可用 postOrderly,它统一 post 到主线程 Handler 队列,按入队顺序执行。
9.3 同一个 observer 重复注册
ExternalLiveData.observe 沿用了官方 LiveData 的去重逻辑:同一个 observer 对象重复 observe 会被忽略,但绑定到不同 LifecycleOwner 会抛异常。
9.4 类型安全
kotlin
LiveEventBus.get("login_ok", UserInfo.class)
.observe(this, userInfo -> { ... });
with(key, type) 的 type 并不改变底层存储类型,主要用于 IDE 推断和运行期 ObserverWrapper 的异常捕获。传错类型可能导致 ClassCastException,框架里已经 catch 并打印日志:
erlang
catch (ClassCastException e) {
logger.log(Level.WARNING, "class cast error on message received: " + t, e);
}
10. 总结
LiveEventBus 跨 Activity 通讯的精髓非常紧凑:
- 单例
LiveEventBusCore+HashMap<String, LiveEvent>:全局共享消息通道。 LiveEvent内部持有一个LifecycleLiveData:所有订阅同一 key 的 Activity/Fragment 共享同一个LiveData。ExternalLiveData重写shouldBeActive:把激活阈值从默认的STARTED降到CREATED,让 Activity 从onCreate起就能收到消息,且生命周期销毁后自动解绑。ObserverWrapper.preventNextEvent:在保留 LiveData 粘性的基础上,给普通observe增加"非粘性"语义。
理解了这四点,就能明白为什么 Activity A 的一条 post 可以无缝地到达 Activity B,同时还能保证生命周期安全和内存安全。