美文网首页
Andorid-JetPack-LiveData组件用法和源码解

Andorid-JetPack-LiveData组件用法和源码解

作者: 信仰年輕 | 来源:发表于2021-07-06 14:53 被阅读0次

    本文目标

    理解并掌握LiveData组件用法和原理

    1.什么是LiveData

    • LiveData组件是Jetpack推出的基于观察者的消息订阅/分发组件,具有宿主(Activity,Fragment)生命周期感知能力,这种感知能力可确保LiveData仅分发消息给处于活跃状态的观察者,即只有处于活跃状态的观察者才能收到消息
    • LiveData的消息分发机制,是以往的Handler,EventBus,RxjavaBus无法比拟的,他们不会顾及到当前页面是否可见,一股脑的有消息就发送.导致即便应用在后台,页面不可见,还在做一些无用的绘制,细心的小伙伴可以发现微信消息列表是在可见状态时才会更新列表最新消息的

    活跃状态:Observer所在宿主处于STARTED,RESUMED状态

    2.基本用法

    • MutableLiveData
      我们在使用LiveData的做消息分发的时候,需要使用到这个子类.其实MutableLiveData只是继承了LiveData,然后重写了postValue(T)setValue(T),把父类的protected改成了public,之所以这么设计,是考虑到单一开闭原则,只有拿到MutableLiveData对象才可以发送消息,LiveData对象只能接受消息,避免拿到LiveData对象时既能发消息也能收消息的混乱使用.
    public class MutableLiveData<T> extends LiveData<T> {
    
        /**
         * Creates a MutableLiveData initialized with the given {@code value}.
         *
         * @param value initial value
         */
        public MutableLiveData(T value) {
            super(value);
        }
    
        /**
         * Creates a MutableLiveData with no value assigned to it.
         */
        public MutableLiveData() {
            super();
        }
    
        @Override
        public void postValue(T value) {
            super.postValue(value);
        }
    
        @Override
        public void setValue(T value) {
            super.setValue(value);
        }
    }
    
    • MediatorLiveData
      1.可以统一观察多个LiveData的发射的数据进行统一处理
      2.同时也可以作为一个LiveData,被其他Observer观察
    //创建两个长的差不多的LiveData对象
    MutableLiveData<String> liveDat1=new MutableLiveData<>();
    MutableLiveData<String> liveDat2=new MutableLiveData<>();
    
    //在创建一个聚合类MediatorLiveData
    MediatorLiveData<String> allLiveData=new MediatorLiveData<>();
    
    //可以观察到
    Observer<String> observer = new Observer<String>() {
          @Override
         public void onChanged(String s) {
            Log.i("yd","onChanged刷新一次");
        }
    };
    //分别把上面创建的两个LiveData对象添加进来
    allLiveData.addSource(liveDat1,observer );
    allLiveData.addSource(liveDat2,observer );
    
    //一旦liveDat1或liveDat2发送了新的数据,observer便可以观察到,以便统一处理更新UI
    

    3.黏性消息实现原理

    • 黏性消息分发流程,即新注册的Observer也能接受到前面发送的最后一条数据,通俗来说就是先发射事件,然后在注册观察者,照样能收到

    我们从LiveDatapublic void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)方法看起,来直接上源码

    public abstract class LiveData<T> {
        @MainThread
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
            assertMainThread("observe");
            if (owner.getLifecycle().getCurrentState() == DESTROYED) {
                // ignore
                return;
            }
            //1,把observer包装成 LifecycleBoundObserver
            LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
            //存到map集合中,有消息就去分发
            ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
            if (existing != null && !existing.isAttachedTo(owner)) {
                throw new IllegalArgumentException("Cannot add the same observer"
                        + " with different lifecycles");
            }
            if (existing != null) {
                return;
            }
            //3.把上面包装后的对象 注册到 `Lifecycle`之中
            owner.getLifecycle().addObserver(wrapper);
        }
    }
    

    该方法主要做了两件事

    • 1.把observer包装成 LifecycleBoundObserver具有生命周期边界的观察者,也就是说宿主状态是STARTEDRESUMED才会接受数据,其他状态不接受数据
    • 2.存到map集合中,有消息就去分发,key:我们传进来的Observer对象,value:包装成的LifecycleBoundObserver对象
    • 3.把上面包装后的对象 注册到 Lifecycle之中,这里就是LiveData利用Lifecycle的地方,能感知生命周期的关键地方,初次注册,宿主每次生命周期的变化都会回调onStateChanged方法,也就是说会回调LifecycleBoundObserveronStateChanged()方法,
      来我们看下LifecycleBoundObserver
    public abstract class LiveData<T> {
    
        class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
            @NonNull
            final LifecycleOwner mOwner;
    
            LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
                super(observer);
                mOwner = owner;
            }
    
            //宿主的状态是否处于活跃状态,其实就是判断宿主是否是STARTED或RESUMED
            @Override
            boolean shouldBeActive() {
                return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
            }
    
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                //1.宿主被销毁事件,则从liveData移除该观察者,流程结束
                if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                    removeObserver(mObserver);
                    return;
                }
                //2.如果宿主的状态为活跃状态STARTED,RESUMED,则分发最新数据到每个观察者
                activeStateChanged(shouldBeActive());
            }
    
            @Override
            boolean isAttachedTo(LifecycleOwner owner) {
                return mOwner == owner;
            }
    
            @Override
            void detachObserver() {
                mOwner.getLifecycle().removeObserver(this);
            }
        }
    }
    

    onStateChanged(Event event)方法中,

    • 1.宿主被销毁事件,则从liveData移除该观察者,流程结束
    • 2.activeStateChanged(shouldBeActive());这行代码,如果宿主的状态是活跃的为STARTED,RESUMED,则分发最新数据到每个观察者,
      具体是如何进行的我们可以追进去看下
    public abstract class LiveData<T> {
    
       private abstract class ObserverWrapper {
            final Observer<? super T> mObserver;
            boolean mActive;
            int mLastVersion = START_VERSION;
    
            ObserverWrapper(Observer<? super T> observer) {
                mObserver = observer;
            }
    
            void activeStateChanged(boolean newActive) {
                if (newActive == mActive) {
                    return;
                }
                mActive = newActive;
                //没有任何一个观察者处于活跃状态
                boolean wasInactive = LiveData.this.mActiveCount == 0;
                LiveData.this.mActiveCount += mActive ? 1 : -1;
               //1.当且仅当有一个观察者的时候才会触发
                if (wasInactive && mActive) {
                    onActive();
                }
               //2.如果没有任何一个活跃的观察者,则会触发
                if (LiveData.this.mActiveCount == 0 && !mActive) {
                    onInactive();
                }
                //3.如果宿主的状态是活跃的为STARTED,RESUMED,则分发最新数据到每个观察者,
                if (mActive) {
                    dispatchingValue(this);
                }
            }
        }
    }
    
    • 1.做一些判断,当且仅当有一个观察者的时候才会触发onActive()方法,该方法是空方法(官方留给我们的口子)
    • 2.如果没有任何一个活跃的观察者,则会触发onInactive();方法,该方法是空方法(官方留给我们的口子)
    • 3.如果宿主的状态是活跃的为STARTED,RESUMED,则分发最新数据到每个观察者,触发dispatchingValue(this);
      继续往下追
    public abstract class LiveData<T> {
    
        void dispatchingValue(@Nullable ObserverWrapper initiator) {
            if (mDispatchingValue) {
                mDispatchInvalidated = true;
                return;
            }
            mDispatchingValue = true;
            do {
                mDispatchInvalidated = false;
                //如果传入的对象不为空,则直接调用分发事件方法
                if (initiator != null) {
                    considerNotify(initiator);
                    initiator = null;
                } else {
                    //为空,说明是从 setValue方法进来,的需要for循环遍历一遍,然后把事件分发给观察者
                    for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                            mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                        //该行代码中真正的分发了事件
                        considerNotify(iterator.next().getValue());
                        if (mDispatchInvalidated) {
                            break;
                        }
                    }
                }
            } while (mDispatchInvalidated);
            mDispatchingValue = false;
        }
    }
    
    • 1.如果传入的对象initiator不为空,则直接调用分发事件方法
    • 2.如果传入的对象initiator为空,说明是从 setValue方法进来,的需要for循环遍历一遍,然后把事件分发给观察者
      不论对象initiator是否为空,最后都会调用considerNotify(iterator.next().getValue());
      这行代码才是真正的去分发事件
    public abstract class LiveData<T> {
        private void considerNotify(ObserverWrapper observer) {
            //1.如果观察者所在的宿主不活跃了,不分发
            if (!observer.mActive) {
                return;
            }
            //判断观察者是否处于活跃状态
            if (!observer.shouldBeActive()) {
                observer.activeStateChanged(false);
                return;
            }
            //2.如果observer.mLastVersion >= LiveData的mVersion,不分发
            if (observer.mLastVersion >= mVersion) {
                return;
            }
            observer.mLastVersion = mVersion;
            //3.分发数据
            observer.mObserver.onChanged((T) mData);
        }
    }
    

    上面的considerNotify(ObserverWrapper observer)方法里面会做一些判断

    • 1.如果观察者所在的宿主不活跃了,不分发
    • 2.如果observer.mLastVersion >= LiveData的mVersion不分发,最初 observer.mLastVersion初始化值为-1,然后LiveDatamVersion在创建之初也等于-1,如果LiveData发送过数据了,这个mVersion就不等于-1了,每次setValue(T value)的时候都会mVersion++,所以第一次注册数据的时候,
      observer.mLastVersion = -1 , mVersion=0,-1 >= 0么?显然条件不满足,然后就会执行下面的数据分发,就会出现黏性事件
    • 3.分发数据
    4.普通消息分发流程
    • 即调用postValue,setValue才会触发消息的分发

    来直接上源码,先看postValue(T value)
    public abstract class LiveData<T> {
        private final Runnable mPostValueRunnable = new Runnable() {
            @SuppressWarnings("unchecked")
            @Override
            public void run() {
                Object newValue;
                synchronized (mDataLock) {
                    newValue = mPendingData;
                    mPendingData = NOT_SET;
                }
                //直接调用setValue
                setValue((T) newValue);
            }
        };
    
        protected void postValue(T value) {
            boolean postTask;
            synchronized (mDataLock) {
                //1.先把消息保存成成员变量mPendingData
                postTask = mPendingData == NOT_SET;
                mPendingData = value;
            }
            if (!postTask) {
                return;
            }
            //2.用handler把消息发送到主线程中
            ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
        }
    }
    

    该方法可以用在子线程,所以这里会使用handler.post先发送到主线程,在分发消息

    • 1.先把消息保存成成员变量mPendingData
    • 2.用handler把消息发送到主线程中
    • 3.在Runnable中,直接调用setValue((T) newValue);
      接下来看下setValue(T value)
        @MainThread
        protected void setValue(T value) {
            assertMainThread("setValue");
            mVersion++;
            mData = value;
            dispatchingValue(null);
        }
    

    mVersion++记录当前发送的消息的次数,用于和observerversion作对比,防止消息重复,
    接下来看dispatchingValue(@Nullable ObserverWrapper initiator),流程就和分析黏性事件的后面流程一样了,最后会调用considerNotify(iterator.next().getValue());经过一系列判断,真正的把事件发送出去

    相关文章

      网友评论

          本文标题:Andorid-JetPack-LiveData组件用法和源码解

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