LiveData 真香,你确定不来试试?

457 阅读3分钟

前言

前段时间忙着新项目的直播功能,终于在提测以后有点时间来看看源码了。直播项目在确定方案以后,根据 sdk 提供的文档和 demo ,花了两天时间对直播 sdk 进行二次封装,将通用逻辑分层,以后的项目就可以实现快速接入。通过直播sdk的接入踩坑,也算是对音视频开发有了些了解,自己的技术方向就定位在音视频、ndk,之后也会出篇直播相关的技术博客。

首先在看源码以前,先提出几个疑问

  1. LiveData 怎样根据生命周期来通知观察者
  2. LiveData 怎样存储数据
  3. 为什么主线程调用 setVaule(),子线程使用 postVaule()

相关链接

Google Git LiveDataCore

从源码的角度深入理解SafeIterableMap

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 调度到主线程