一句话总结:
观察者模式就像「班级群通知」—— 老师(被观察者)发消息,学生(观察者)自动接收,Android 里的 LiveData、点击事件、广播都用这套机制实现消息传递!
一、观察者模式在 Android 的经典应用
1. LiveData 的数据驱动更新
源码实现:
// frameworks/base/core/java/androidx/lifecycle/LiveData.java
public abstract class LiveData<T> {
// 存储观察者的安全集合
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
// 注册观察者(自动绑定生命周期)
public void observe(LifecycleOwner owner, Observer<? super T> observer) {
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
mObservers.put(observer, wrapper);
owner.getLifecycle().addObserver(wrapper);
}
// 数据变更时通知观察者
protected void setValue(T value) {
mData = value;
dispatchingValue(null);
}
private void dispatchingValue(ObserverWrapper initiator) {
for (Map.Entry<Observer<? super T>, ObserverWrapper> entry : mObservers) {
considerNotify(entry.getValue()); // 逐个通知观察者
}
}
}
设计亮点:
- 生命周期感知:当 Activity/Fragment 销毁时自动移除观察者,避免内存泄漏
- 版本控制:每个数据更新增加版本号,避免重复通知
- 线程安全:
SafeIterableMap支持并发遍历与修改
二、底层原理深入解析
1. 观察者注册与通知流程
用户调用 liveData.observe()
→ 创建 LifecycleBoundObserver 包装类
→ 将观察者存入 SafeIterableMap
→ 当 LiveData 数据变化(setValue())
→ 遍历所有观察者
→ 检查生命周期状态(活跃才通知)
→ 调用 observer.onChanged()
2. 生命周期绑定实现(LifecycleBoundObserver)
// 内部类实现生命周期监听
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(observer); // 自动移除销毁的观察者
}
activeStateChanged(shouldBeActive());
}
}
3. 线程切换机制(postValue)
// 在后台线程更新数据
public void postValue(T value) {
// 将值存入队列
ArchTaskExecutor.getInstance().postToMainThread(() -> setValue(value));
}
- 原理:通过
ArchTaskExecutor切换到主线程执行setValue()
三、其他典型应用场景
1. View 的点击事件监听
// 观察者接口
public interface OnClickListener {
void onClick(View v);
}
// 被观察者 View 的实现
public class View implements OnClickListener {
private OnClickListener mOnClickListener;
public void setOnClickListener(OnClickListener l) {
mOnClickListener = l; // 注册观察者
}
// 触发通知
public boolean performClick() {
if (mOnClickListener != null) {
mOnClickListener.onClick(this);
return true;
}
return false;
}
}
2. BroadcastReceiver 的广播系统
// 注册观察者
IntentFilter filter = new IntentFilter("MY_ACTION");
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// 处理广播
}
}, filter);
// 系统发送广播(被观察者通知)
Intent broadcast = new Intent("MY_ACTION");
sendBroadcast(broadcast);
底层机制:通过 ActivityManagerService 管理广播队列,跨进程分发
四、观察者模式的优势与挑战
优势:
- 解耦:发送方和接收方无需直接引用
- 动态订阅:运行时灵活添加/移除观察者
- 广播通信:一对多消息传递效率高
挑战:
- 内存泄漏:忘记反注册观察者(如未取消广播注册)
- 性能问题:观察者过多或处理耗时操作导致卡顿
- 线程安全:跨线程通知需同步机制(如 LiveData 的
postValue)
五、最佳实践与避坑指南
该做的:
- 使用
LiveData替代普通观察者:自动处理生命周期 - 在
onDestroy中反注册:如unregisterReceiver() - 耗时操作切到子线程:避免在主线程的观察者中处理复杂逻辑
不该做的:
- 在
Activity中直接持有观察者引用:用弱引用或自动解绑 - 频繁通知无意义更新:如数据未变化也应避免触发
onChanged - 在观察者中更新 UI 不加判断:先检查
isAdded()或isResumed()
六、源码中的设计模式变种
1. 事件总线(EventBus)的粘性事件
// 存储粘性事件
private final Map<Class<?>, Object> stickyEvents = new ConcurrentHashMap<>();
// 新观察者注册时收到历史事件
public void register(Object subscriber) {
// 检查并发送粘性事件
for (Map.Entry<Class<?>, Object> entry : stickyEvents.entrySet()) {
postToSubscription(subscriber, entry.getValue(), true);
}
}
2. WorkManager 的任务状态观察
WorkManager.getInstance(context)
.getWorkInfoByIdLiveData(uploadWork.id)
.observe(this, workInfo -> {
if (workInfo.getState() == State.SUCCEEDED) {
// 处理任务完成
}
});
七、总结口诀
「观察模式像群聊,LiveData 是代表
注册监听等通知,生命周期自动管
点击广播都用它,忘记反注会泄漏
核心要点:
- 使用
LiveData+ViewModel实现数据驱动 UI - 避免在观察者中直接操作视图(用数据绑定或 ViewModel 中转)
- 跨线程通知必须用
postValue或Handler
Android 观察者三剑客:
| 场景 | 被观察者 | 观察者 |
|---|---|---|
| 数据变化 | LiveData | Observer |
| 用户交互 | View | OnClickListener |
| 系统事件 | Broadcast | BroadcastReceiver |