<
>

Android Jetpack 组件LiveData源码解析

2023-03-11 08:37:52 来源:易采站长站 作者:

目录
前言基本使用疑问源码分析ObserverObserverWrapperLifecycleBoundObserverMutableLiveDatapostValuesetValue问题答疑LiveData 特性引出的问题问题解决最后

前言

本文来分析下>

基本使用

一般来说>

示例代码:

MainViewModel.kt

class MainViewModel: ViewModel() {
    // 定义 LiveData 注意这里给了 0 作为初始值
    val number = MutableLiveData<Int>(0)
    fun add(){
        // 相当于 number.setValue(number.getValue() + 1)
        number.value = number.value?.plus(1)
    }
    fun sub(){
        // 相当于 number.setValue(number.getValue() - 1)
        number.value = number.value?.minus(1)
    }
}

MainACtivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 获取 ViewModel 实例
        val vm = ViewModelProvider(this).get(MainViewModel::class.java)
        // 调用 ViewModel 方法 进行加法操作
        bnAdd.setOnClickListener {
             vm.add()
        }
        // 调用 ViewModel 方法 进行减法操作
        bnSub.setOnClickListener {
            vm.sub()
        }
        // 观察 LiveData 变化, Observer 是接口,kotlin 写法简化
        vm.number.observe(this, Observer {
            tvNumber.text = it.toString()
        })
    }
}

XML 非常简单就不贴了,看下效果图:

疑问

很简单的功能,但是有两个问题需要注意:

    在>数值发生变化后,进行横竖屏切换后 TextView 依然保持着最新值(如果 number 作为普通 Int 放在 Activity 中,当 Activity 由于横竖屏切换导致重建会重新变为 0);

    本文将以这两个问题作为切入点,对 LiveData 源码进行分析。

    源码分析

    Observer

    从实例代码中很容易看出这是典型的观察者模式,当>

    public interface Observer<T> {
        void onChanged(T t);
    }
    

    当 LiveData 发生变化时,就会触发其观察者的 onChanged 方法,并传递最新值;

    再看一下其添加订阅时的源码:

    public abstract class LiveData<T> {
        //...
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
            // 检查是否在主线程
            assertMainThread("observe");
            // 如果观察者所在组件的生命周期为 DESTROYED 则直接 return
            if (owner.getLifecycle().getCurrentState() == DESTROYED) {
                return;
            }
            // LifecycleBoundObserver 实现了 ObserverWrapper
            // 理解为这是对 观察者 Observer 的一层包装类即可
            LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
            // mObservers 是一个 Map 容器,原始的 Observer 为 key,包装后的 wrapper 为 value
            ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
            // 同一个 observer 不能在不同的生命周期组件中进行订阅
            if (existing != null && !existing.isAttachedTo(owner)) {
                throw new IllegalArgumentException("Cannot add the same observer"
                        + " with different lifecycles");
            }
            // 重复订阅直接return
            if (existing != null) {
                return;
            }
            // LifecycleBoundObserver 利用 Lifecycle 实现自动解绑
            // Lifecycle 原理详见我之前的博客
            owner.getLifecycle().addObserver(wrapper);
        }
        // ...
    }
    

    从源码中得知订阅必须在主线程(这一点也非常适用于 Android 的 UI 更新), 订阅后会放入一个 Map 容器中存储;

    ObserverWrapper

    接着来看一下>

    private abstract class ObserverWrapper {
        final Observer<? super T> mObserver; // Observer 原始对象
        boolean mActive; // 是否激活
        int mLastVersion = START_VERSION; // 版本号 默认 -1
        ObserverWrapper(Observer<? super T> observer) {
            mObserver = observer; // 赋值
        }
        abstract boolean shouldBeActive(); // 抽象方法
        boolean isAttachedTo(LifecycleOwner owner) {
            return false;
        }
        void detachObserver() {
        }
        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) { // 如果值一样则返回
                return;
            }
            mActive = newActive; // 不一样则更新 mActive
            changeActiveCounter(mActive ? 1 : -1); // 记录有多少个激活状态的observer
            // 注意这里,如果mActive是从false变更为true 则调用一次 dispatchingValue
            // dispatchingValue 的源码下面再分析
            if (mActive) { 
                dispatchingValue(this);
            }
        }
    }
    

    LifecycleBoundObserver

    接着看一下>

    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;
        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer); // 父类构造器 赋值
            mOwner = owner;
        }
        @Override
        boolean shouldBeActive() { // 判断是否是激活状态
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }
        // 如果再 activity 中进行 observer
        // 当 activity 生命周期发生变化时 会回调到这里
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            // 自动解绑
            if (currentState == DESTROYED) { 
                // removeObserver 内部会将 observer 从 map 容器中移除
                // 并且调用其 detachObserver 方法
                removeObserver(mObserver);
                return;
            }
            Lifecycle.State prevState = null;
            while (prevState != currentState) {
                prevState = currentState;
                // activeStateChanged 上面已经说过了
                // 如果 mActive 由 fasle 变更为 true 会执行一次 dispatchingValue
                activeStateChanged(shouldBeActive());
                currentState = mOwner.getLifecycle().getCurrentState();
            }
        }
        // ...
    }
    

    MutableLiveData

    上述的观察者相关的重要源码已经分析完,接着来看一下示例代码中定义的>

    public class MutableLiveData<T> extends LiveData<T> {
        public MutableLiveData(T value) {
            super(value);
        }
        public MutableLiveData() {
            super();
        }
        @Override
        public void postValue(T value) {
            super.postValue(value);
        }
        @Override
        public void setValue(T value) {
            super.setValue(value);
        }
    }
    

    继承自 LiveData,作用很明显暴露出其 postValue、setValue 方法,那么就先来看一下这两个方法调用逻辑

    postValue

    先来看看>

    public abstract class LiveData<T> {
        protected void postValue(T value) {
            boolean postTask;
            synchronized (mDataLock) {
                // mPendingData 默认值为 NOT_SET
                postTask = mPendingData == NOT_SET;
                // 调用 postValue 后,会赋值成传进来的 value
                mPendingData = value; 
            }
            if (!postTask) { // 第一次调用 肯定为 true
                return;
            }
            // 核心在于这一行,postToMainThread 
            // 看名字也知道是切换到主线程去执行 mPostValueRunnable
            ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
        }
    }
    

    ArchTaskExecutor.getInstance() 会初始化其内部的 mDelegate 变量,其最终实现是 DefaultTaskExecutor;DefaultTaskExecutor 内部包含一个主线程 Handler,其 postToMainThread 方法就是利用 Handler 将 runnable 发送至主线程执行。这里面的源码比较简单,就不贴出来细节了,看一下 mPostValueRunnable 具体执行了什么:

    private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) { // 加锁同步
                newValue = mPendingData; // 获取最新传递过来的值
                mPendingData = NOT_SET; // 将 mPendingData 恢复为默认值
            }
            // 最终还是调用了 setValue
            setValue((T) newValue);
        }
    };
    

    可以看出 postValue 可以在任意线程调用,最终都会被切换到主线程调用 setValue,但是需要注意,频繁调用 postValue 可能会只保留最后一次的值,因为每次 postValue 会导致 mPendingData 设置为新的值,但如果多次 postValue 在子线程执行,但是主线程还没有来得及执行 mPostValueRunnable,会导致 mPendingData 没有被恢复为 NOT_SET,那么 postTask 即为 false,但 mPendingData 会设置为最新值,当 mPostValueRunnable 执行时从 mPendingData 中获取的也是最新值。

    setValue

    postValue>

    public abstract class LiveData<T> {
        static final int START_VERSION = -1;
        private volatile Object mData;
        private int mVersion
        // 带初始值的构造器
        public LiveData(T value) {
            mData = value; // 直接给 mData 赋值
            mVersion = START_VERSION + 1; //版本号 +1,也就是 0
        }
        // 无参构造器
        public LiveData() {
            mData = NOT_SET;
            mVersion = START_VERSION; // 版本号默认 -1
        }
        protected void setValue(T value) {
            // 内部根据 Looper 判断是否在主线程,不在主线程则抛出异常
            assertMainThread("setValue");
            // 版本号 +1
            mVersion++;
            // LiveData 的数据,也就是被观察的数据,设置为最新值
            mData = value;
            // 这里是重点
            dispatchingValue(null);
        }
    }
    

    从源码中得知,setValue 只能从主线程调用,内部对版本号进行++操作,并且设置 mData 为最新值,最终调用 dispatchingValue:

    // 用于保存其观察者 Observer,Observer 会包装成
    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
            new SafeIterableMap<>();
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) { // 默认为 false 
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true; // 进入方法后设置为 true
        do {
            mDispatchInvalidated = false; 
            // setValue 传进来的是 null 不会进入这个 if
            // initiator 实际上就是观察者,如果传递进来一个观察者对象
            // 则只进行一次 considerNotify 方法调用
            if (initiator != null) { 
                considerNotify(initiator);
                initiator = null;
            } else { // 遍历自身的观察者
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    // 调用 considerNotify 将观察者传入
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false; // 方法执行结束前 设置为 false
    }
    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) { // 未激活状态直接返回
            return;
        }
        // 判断是否可以是激活状态
        // LifecycleBoundObserver 中则是判断所在组件的生命周期是否为激活状态
        if (!observer.shouldBeActive()) { 
            observer.activeStateChanged(false); // 将 observer 的 mActive 设置为 fasle
            return;
        }
        // 如果 observer 的版本号 大于 LiveData 本身的版本号 则直接返回
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        // 将 observer 的版本号和 LiveData 本身的版本号同步
        observer.mLastVersion = mVersion;
        // 触发其 onChanged 方法回调
        observer.mObserver.onChanged((T) mData);
    }
    

    setValue 的源码并不复杂,总结一下:

      mVersion 版本号 ++ 操作,并且 mData 设置为最新数据;dispatchingValue(null) 遍历观察者容器,对符合条件的观察者调用其 onChanged 方法回调。

      问题答疑

      从源码中我们可以了解到,当调用>

      又因为 Lifecycle 会在观察组件生命周期之后就会进行状态同步,所以我们再调用 LiveData.observer 之后会触发一次 activeStateChanged,导致 observer 的 mActive 由 fasle 变为 true,所以会进行一次 dispatchingValue;

      在示例代码中我们给 MainViewModel 中的 number 赋值了初始值 0,那么初始化时会调用 LiveData 有参的构造函数,其中对 mVersion 进行了 +1 操作,此时的 LiveData 中的 mVersion 变为了 0,而 observer 中的 mLastVersion 为 -1,所以会进行一次分发,所以 TextView 的 text 被设置为了 0;

      而第二个问题和上述的原因类似,不过特殊点在于 number 是被定义在在 ViewModel 中,开头也提到过 ViewModel 暂时可以理解为生命周期长于 Activity 的对象,那么当 Activity 由于横竖屏切换导致重建后, ViewModel 中的数据并没有清楚,LiveData 自然保持着他的 mData 最新值以及其 mVersion 版本号,当 Actvitiy 重新调用 LiveData.observer 进行订阅时,传入的 observer 的 mVersion 已经变为 -1,所以同样会触发一次 onChanged 回调得到最新值;

      LiveData>

      上述问题答疑中其实可以看出 LiveData 订阅后可以获取最新值这在数据流中属于粘性 事件。在示例代码中,横竖屏切换后仍然可以获取最新的值,这比较符合用户使用习惯。但实际开发中往往有着更复杂的场景,比如:定义一个 LiveData<Boolean>(false) 表示是否需要展示加载中弹窗,假设需求是用户点击按钮后展示,此时用户点击按钮,将其设置为 true,那么此时 Activiy 发生重建导致生命周期重新走一遍,此时的 LiveData 的 value 仍然为 true,重建后用户并没有点击按钮但弹窗仍然会显示;

      这是一个很常见的业务需求,发生这种问题的根本原因是生命周期重新走之后导致 observer 的 mLastVersion 变更为 -1,而 LiveData 的 mVersion 不变,导致重新触发 onChanged 方法回调;

      遇到这种情况该怎么办呢?难道 LiveData 设计的有问题?我认为这并非 google 官方设计的不好,而是 LiveData 本身就应该作用于时时刻刻需要获取最新值的场景,而并非所有的数据都需要放到 ViewModel 中用 LiveData 包裹。上述的问题更多的我认为是 LiveData 滥用而导致的。 但 LiveData 的 onChanged 的数据变化后进行回调很多场景使用起来又很方便,该怎么办?

      问题解决

      既然已经知道原因,源码又了解的差不多,很容易就能找到问题的切入点;那就是>

      还有更好的办法,SingleLiveData!我最初看到这个类是在 github 中的一个 issue 中,后来网上流传了很多版本,其原理是对 LiveData 进行包装,内部定义一个 HashMap<Observer<in T>, AtomicBoolean> 容器,重写其 observer 订阅方法,每个 observer 对应一个 AtomicBoolean 对象,在 setValue 之前先遍历将所有的 AtomicBoolean 设置为 true,接着重写其 observer 包装一层,在分发时判断并修改 AtomicBoolean 为 false。

      我觉得这也是比较好的规避问题的方法,这里就随便贴一个了:

      class SingleLiveData<T> : MutableLiveData<T>() {
          private val mPendingMap = HashMap<Observer<in T>, AtomicBoolean>()
          @MainThread
          override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
              val lifecycle = owner.lifecycle
              if (lifecycle.currentState == Lifecycle.State.DESTROYED) {
                  return
              }
              mPendingMap[observer] = AtomicBoolean(false)
              lifecycle.addObserver(LifecycleEventObserver { source: LifecycleOwner?, event: Lifecycle.Event ->
                  if (event == Lifecycle.Event.ON_DESTROY) {
                      mPendingMap.remove(observer)
                  }
              })
              super.observe(owner) { t: T ->
                  val pending = mPendingMap[observer]
                  if (pending != null && pending.compareAndSet(true, false)) {
                      observer.onChanged(t)
                  }
              }
          }
          @MainThread
          override fun observeForever(observer: Observer<in T>) {
              mPendingMap[observer] = AtomicBoolean(false)
              super.observeForever(observer)
          }
          @MainThread
          override fun removeObserver(observer: Observer<in T>) {
              mPendingMap.remove(observer)
              super.removeObserver(observer)
          }
          @MainThread
          override fun removeObservers(owner: LifecycleOwner) {
              mPendingMap.clear()
              super.removeObservers(owner)
          }
          @MainThread
          override fun setValue(t: T?) {
              for (value in mPendingMap.values) {
                  value.set(true)
              }
              super.setValue(t)
          }
      }
      

      最后

      我对于>

      以上就是Android Jetpack 组件LiveData源码解析的详细内容,更多关于Android Jetpack LiveData的资料请关注易采站长站其它相关文章!

暂时禁止评论

微信扫一扫

易采站长站微信账号