面试官:我看你简历上有写 LiveData,那谈谈LiveData事件机制

Posted 初一十五啊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试官:我看你简历上有写 LiveData,那谈谈LiveData事件机制相关的知识,希望对你有一定的参考价值。

💡前言

相信很多人在职业生涯的面试过程中都会被问到关于LiveData相关的。

今天就来分析一下LiveData的粘性事件以及LiveData订阅与数据分发。

另外总结一下LiveDate事件事件一共有以下内容:

LiveDate粘性事件Framework源码分析
Jetpack中的状态机是如何管理生命周期
Hook实现LiveDate非粘性功能
LiveDate递归调用源码是如何做容错的
企业级LiveDateBus封装实现

💡 一丶livedata粘性事件

粘性事件:相对比普通事件,粘性事件支持先发送事件,再去注册订阅者。一旦完成订阅动作,这个订阅者就会接收到该粘性事件。

所以粘性其实就可以理解为观察者模式的升级,让观察者与被观察者对象之间更加的粘合。

举个栗子,我们利用livedata来做APP的全局状态管理

   object GlobalState 
       val jcTestNumberLd: MutableLiveData<Int> = MutableLiveData<Int>()

   

然后在 Fragment 以及 Activity 中观察该 jcTestNumberLd

  /** 观察 GlobalState 的 Activity */
  class JcTestActivity : BaseVmDbActivity<MainViewModel, ActivityJcTestBinding>() 

      override fun initView() 
          viewBinding.incButton.setOnClickListener 
              GlobalState.jcTestNumberLd.value =
                  if (GlobalState.jcTestNumberLd.value == null) 
                      1
                   else 
                      GlobalState.jcTestNumberLd.value!!.toInt().inc()
                  
          
      

      override fun initObserve() 
          GlobalState.jcTestNumberLd.observe(this, 
              Log.e(TAG, "initObserve: jctestNumber = $it")
          )

      

      ........
  

  /** 观察 GlobalState 的 Fragment */
  class EventFragment : BaseVmDbFragment<EventViewModel, FragmentEventBinding>() 

      override fun setObservers() 
          GlobalState.jcTestNumberLd.observe(viewLifecycleOwner, 
              Log.e(TAG, "setObservers: jctestNumber = $it", )
          )
      

      ........
  

注意:这里例子中的 EventFragment 并不是关联到 JcTestActivity 的。用户会先进入到 JcTestActivity,然后由用户控制进入到另一个Activity中,加载 EventFragment

我们来执行一下以下五步操作,来看一下输出的日志。

  • 当我们第一次进入 JcTestActivity 时,注册了观察者,没有接收到观察事件,所以也就不会执行观察动作。
  • 然后我们点击自增按钮为jcTestNumberLd 赋予新值,接收到观察事件,执行观察动作,输出 1。
  • 再次点击自增按钮,有观察事件,执行观察动作,输出 2。
  • 再次点击自增按钮,有观察事件,执行观察动作,输出 3。
  • 然后我们到 EventFragment 中,注册新的观察者,发现直接接收到观察事件,执行观察动作,输出 3。

输出结果:

  E/JcTestActivity: initObserve: jctestNumber = 1
  E/JcTestActivity: initObserve: jctestNumber = 2
  E/JcTestActivity: initObserve: jctestNumber = 3

  E/EventFragment: setObservers: jctestNumber = 3

这就是粘性事件!所以说,LiveData是粘性的。

💡二丶LiveData 是怎么实现粘性的呢?

在知道LiveData是粘性后,我不经问自己:它是怎么实现粘性的呢?

这里我们先来回顾一下EventBus粘性事件的实现原理。

EventBus在发送粘性事件时,会将这粘性事件存到一个叫做 stickyEvents 的集合中,然后等注册订阅新的观察者对象时,会去遍历该集合中的粘性事件,如果有找到对应的粘性事件,就将该粘性事件发送给该观察者。(如果你对EventBus粘性事件不熟悉,可以点击EventBus 源码解析(很细 很长)进一步了解学习。)

LiveData是不是也是以同样的原理来实现粘性的呢?

  public LiveData(T value) 
      mData = value;
      mVersion = START_VERSION + 1;
  

  /**
   * Creates a LiveData with no value assigned to it.
   */
  public LiveData() 
      mData = NOT_SET;
      mVersion = START_VERSION;
  

LiveData 的构造函数中可以发现有一个 mVersion 参数,它代表着 LiveData 的版本号,每当我们进行 setValue 时,都会让 mVersion 进行自增。

另外,ObserverWrapper 这个观察者包装类中也有一个 int mLastVersion = START_VERSION 版本号。

这两个版本号分别是被观察者对象与观察者对象的版本号,那这二者之间又有什么关系呢?

在判断是否通知观察者的 considerNotify(ObserverWrapper observer) 方法中,会对这两个版本号进行比较。

  private void considerNotify(ObserverWrapper observer) 
      ...省略代码...

     //如果观察者的版本号 >= LiveData的版本号,就说明该观察者已经接收过该观察事件,也就不再分发。
      if (observer.mLastVersion >= mVersion) 
          return;
      
      //反之,分发观察事件给该观察者,让其执行对应的观察动作,并更新观察者的版本号
      observer.mLastVersion = mVersion;
      observer.mObserver.onChanged((T) mData);
  

概括一下:根据比对观察者对象的版本号与LiveData的版本号来判断是否分发当前版本的数据给该观察者。如果观察者对象的版本号大于等于LiveData的版本号,也就说明该观察者已经接收过当前版本的数据了,也就不需要再次分发了(等待下一次数据更新)。反之,则分发当前版本的数据给该观察者,让其执行对应的观察动作,并更新观察者的版本号,也就是更新为LiveData的版本号。

💡三丶Google为何要将LiveData设计成粘性的

LiveData 是可观察的数据存储器类,这样也就意味着存储在LiveData中的数据是会更新的,既然是会更新的,那必定就会存在状态,即最新数据状态。

所以,当数据状态发生改变时(数据发生了更新),LiveData需要告诉所有处于活跃状态的观察者, 让其同步更新数据。这应该很好理解了,因为这就是普通事件,先注册观察者,再去更新被观察者对象,触发观察事件。

那这时,你再去新注册一个观察者对象,你认为它需不需要知道此时LiveData最新的数据呢?

答案是:需要。

因为所有的观察者,都只需要知道LiveData中存储的数据,而且是最新数据。不管我是新注册的观察者,只要你LiveData有了最新数据,就需要告诉我。而关于有无新数据,从代码上体现出来的就是,LiveData.mVersion > Observer.mLastVersion

这也就是粘性事件,先更新被观察者对象,触发观察事件,再去注册观察者,观察者会直接接收到该观察事件,执行对应的观察动作。

它的功能属性导致其只能是粘性的。

💡 四丶LiveData订阅与数据分发

使用

  public class LiveDataActivity extends AppCompatActivity 
 
      MutableLiveData liveData= new MutableLiveData<String>();
 
      void liveDataTest()
          //  任何线程都可以发送数据
          liveData.postValue("postValue");
          // 只有主线程可以发送数据
          // liveData.setValue("setValue")
      
 
      void observeTest()
          //订阅
          liveData.observe(this, new Observer<String>() 
              @Override
              public void onChanged(String data) 
                  //收到数据data
              
          );
          //可以有多个订阅
          liveData.observe(this, new Observer<String>() 
              @Override
              public void onChanged(String data) 
                  //收到数据data
              
          );
      
  

阶段一:
postValue:

  protected void postValue(T value) 
        boolean postTask;
        synchronized (mDataLock) 
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        
        if (!postTask) 
            return;
        
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    
  • 将用户发送的数据给到一个 mPendingData 的变量;
  • 切换到主线程
  • 执行了一个mPostValueRunnable;

mPostValueRunnable:

    volatile Object mPendingData = NOT_SET;
    private int mVersion;
 
    private final Runnable mPostValueRunnable = new Runnable() 
        @SuppressWarnings("unchecked")
        @Override
        public void run() 
            Object newValue;
            synchronized (mDataLock) 
                newValue = mPendingData;
                mPendingData = NOT_SET;
            
            setValue((T) newValue);
        
    ;
  • mPostValueRunnable中将mPendingData给到了新的临时变量newValue;
  • mPendingData的值置为空;
  • 调用setValue(newValue);

setValue:

   private volatile Object mData;
 
    private int mVersion;    
 
    @MainThread
    protected void setValue(T value) 
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    
  • 将数据版本mVersion +1;
  • 将发送的数据给到了mData;
  • 调用分发数据dispatchingValue

看到这里发现,数据其实最后存到了mData中;若想发送订阅消息,肯定得添加订阅者;

阶段二:
添加订阅者,observe():

       //用户使用:
        //liveData.observe(this@LiveDataActivity,
        //    
        //)
 
    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
            new SafeIterableMap<>();
    
 
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) 
        assertMainThread("observe");
        //如果被观察者的生命周期是DESTROYED,就不添加订阅者
        if (owner.getLifecycle().getCurrentState() == DESTROYED) 
            // ignore
            return;
        
        
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
       
        ...
 
        owner.getLifecycle().addObserver(wrapper);
    
  • 将有生命周期的Activity和订阅者Observer传了进来;
  • 判断Activity的生命周期;
  • ActivityObserver封装为一个LifecycleBoundObserver对象;
  • LifecycleBoundObserver放到了mObservers这个Map集合中;
  • mapkey为观察者,value为封装了activity和观察者Observer的对象LifecycleBoundObserver;

LifecycleBoundObserver及它的父类ObserverWrapper

    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver 
        @NonNull
        final LifecycleOwner mOwner;
 
        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) 
            super(observer);
            mOwner = owner;
        
 
        ...
 
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) 
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            if (currentState == DESTROYED) 
                removeObserver(mObserver);
                return;
            
            Lifecycle.State prevState = null;
            while (prevState != currentState) 
                prevState = currentState;
                activeStateChanged(shouldBeActive());
                currentState = mOwner.getLifecycle().getCurrentState();
            
        
 
        ...
 
        @Override
        void detachObserver() 
            mOwner.getLifecycle().removeObserver(this);
        
    
 
 
 
 
    //ObserverWrapper
 
    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;
            changeActiveCounter(mActive ? 1 : -1);
            if (mActive) 
                dispatchingValue(this);
            
        
   
  • 将有生命周期的Activity给到了LifecycleBoundObservermOwner
  • 将观察者给到了LifecycleBoundObserver的父类ObserverWrappermObserver
  • 其实LifecycleBoundObserver就可以获取到ActivitymObserver
  • 上一步,看到将封装后的LifecycleBoundObserver放到了mObservers这个map中;
  • mapkey为观察者,value为封装了activity和观察者Observer的对象LifecycleBoundObserver

阶段三:
分发:
在阶段一setValue()时,调用了dispatchingValue(null);

    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;
    
 
 
 
 
    private void considerNotify(ObserverWrapper observer) 
        if (!observer.mActive) 
            return;
        
        ...
 
        if (observer.mLastVersion >= mVersion) 
            return;
        
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    
  • 当为null时,走到了for循环
  • 循环取出map中的value,而value就是LifecycleBoundObserver;
  • LifecycleBoundObserver中有mObservermObserver就是用户传的观察者;
  • mObserver.onChanged((T) mData);
  • 完成了“主动”分发;

💡到此LiveDate关于粘性事件与订阅和数据分发就讲完啦。

更多Android面试大全总结(全文30W+字.200多个知识点.330张图.38个视频合集)

包含(视频+文字):android基础-性能优化-Framework-compose开源项目-音视频初中高-架构-车载-Flutter-Kotlin-Harmony OS+音视频详细文档。

以上是关于面试官:我看你简历上有写 LiveData,那谈谈LiveData事件机制的主要内容,如果未能解决你的问题,请参考以下文章

对线面试官之MySQL索引篇

对线面试官之MySQL索引篇

面试官问我MySQL索引,我真的是

再见了,Dubbo!

再也不在简历上写熟悉Glide,面试官一波连环炮整麻了!

面试官:看你简历说写精通ThreadLocal,这几道题你都会吗?