美文网首页Android开发
LiveData 真香,你确定不来试试?

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

作者: 毛先森 | 来源:发表于2020-06-02 10:46 被阅读0次

    前言

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

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

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

    相关文章

      网友评论

        本文标题:LiveData 真香,你确定不来试试?

        本文链接:https://www.haomeiwen.com/subject/czoyzhtx.html