前言
前段时间忙着新项目的直播功能,终于在提测以后有点时间来看看源码了。直播项目在确定方案以后,根据 sdk 提供的文档和 demo ,花了两天时间对直播 sdk 进行二次封装,将通用逻辑分层,以后的项目就可以实现快速接入。通过直播sdk的接入踩坑,也算是对音视频开发有了些了解,自己的技术方向就定位在音视频、ndk,之后也会出篇直播相关的技术博客。
首先在看 LiveData 源码以前,先提出几个疑问
- LiveData 怎样根据生命周期来通知观察者
- LiveData 怎样存储数据
- 为什么主线程调用 setVaule(),子线程使用 postVaule()
相关链接
LiveData 类
LiveData 是一个抽象类,其中定义了数据传递的主要逻辑,可以看出遵守开闭原则。在成员变量中有一个 object 对象,用于 postVaule 时锁住 LiveData 对象,防止多线程问题。
内部定义一个 ObserverWrapper 抽象类,处理与 Lifecycle 对应的状态,而 LifecycleBoundObserver 内部类则实现了 ObserverWrapper
LifecycleBoundObserver
内部持有了 LifeCyclerOwner,可获取到当前生命周期的状态,当 Activity、Fragment 销毁时,移除观察者,从而避免内存泄漏。
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
// 如果已经回调 onDestroy(),则移除观察者
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
postValue -子线程使用
子线程传递数据到主线程,首先判断上一次待传递的值 (mPendingData)是否已经发布出去,如果上一次的还未发布则 return,否则使用线程管理器将一个子线程调度到主线程执行
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
setValue -主线程使用
在设置值之前,判断当前是否为主线程,否则抛出异常
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
// 此处设置 null,是为了使用迭代器遍历通知所有处于活跃状态的观察者
dispatchingValue(null);
}
/**
* 1.入参为 null 时,遍历通知
* 2.入参不为空,则指定通知该观察者
*/
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
// 使用迭代器遍历通知所有观察者
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
总结
对于开头提出的问题,在查看源码过后,自己心里已经有了答案
-
LiveData 怎样根据生命周期来通知观察者
LiveData 是 LifeCycler 的分支,也就是说 LiveData 在观察者活跃时通知的特性,是基于 LifeCycler 实现的,因为内部持有了 LifeCyclerOwner,可以通过 LifeCyclerOwner.getLifeCycler() 获取生命周期的状态
-
LiveData 怎样存储数据
LiveData 内部保存了所有观察者的集合,使用 SafeIterableMap 来保存,非线程安全型的,支持在遍历环节修改,SafeIterableMap 内部使用了 WeakHashMap,防止内存泄漏
-
为什么主线程调用 setVaule(),子线程使用 postVaule()
因为最终都会在主线程发布通知,而这两个方法且别在对当前线程的调度,setVaule ()方法会判断当前是否为主线程, postVaule()会将 Runnable 调度到主线程
网友评论