天天看点

多线程调用LiveData的postValue如何保证只展示最新值多线程调用LiveData的postValue如何保证只展示最新值

多线程调用LiveData的postValue如何保证只展示最新值

LiveData简介

LiveData是一个数据持有类,它可以通过观察者模式被android的Activity和Fragment等监听,当LiveData的数据发生变化时,会通过onChanged方法通知页面更新数据。

LiveData的优势在于可以感知组件的生命周期,只有在组件是活跃状态时才会通知组件更新(observe方法),当组件被destroy后,就算LiveData发生了变化也不会回调通知,且destroy后自动取消了组件的监听,避免了内存泄露。

当发生Config Change时(比如屏幕旋转),不需要通过手动处理处理数据的保存( onSaveInstanceState ),LiveData会自动处理。

LiveData更新数据有两个方法,setValue和postValue

  • setValue只能在主线程使用
  • postValue可以在子线程和主线程使用,通过handler回到主线程设置

多线程使用postValue的问题

先贴上部分源代码

protected void postValue(T value) {
   boolean postTask;
   // 锁住
   synchronized (mDataLock) {
      // 当前没有人在处理 post 任务
       postTask = mPendingData == NOT_SET;
       mPendingData = value;
   }
   if (!postTask) {
       return;
   }
   AppToolkitTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
   @Override
   public void run() {
       Object newValue;
       synchronized (mDataLock) {
           newValue = mPendingData;
		   // 处理完毕之后将 mPendingData 置为 NOT_SET
           mPendingData = NOT_SET;
       }
       //noinspection unchecked
       setValue((T) newValue);
   }
};
           

注意一点:mPendingData的类型是private volatile Object的,在主线程的runnable中是用mPendingData的值来更新的。

关于postValue的使用官方文档有这么一句

If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched.
           

大概意思是在主线程执行更新从postValue传过来的值前(就是在runnable的锁代码块完成前),如果调用了多次postValue,那么只有最新一次的值会被更新。

postValue时如何保证这个的呢?

一开始我看这个很疑惑,因为现在假设有两个线程AB先后调用了同一个LiveData的postValue,先A后B,一开始A先拿到postValue中的锁,此时postTask为True,mPendingData变成了A设的值a,然后通过handler走到主线程去执行,但在A拿到runnable中的锁前,线程B提前拿到了postValue中的锁,此时postTask变为False,mPendingData变为了B设的值b,此时B释放锁,然后因为postTask为false直接return,最后A再在主线程更新,这时不就是用值a来更新了吗?这怎么能做到只有最新一次的值被更新?

LiveData通过volatile保证多次postValue只会更新一次最新值

是的,因为mPendingData是volatile的,所以上述情况下,B更新mPendingData后,主线程中的mPendingData也会马上更新从a为b(实际情况其实是读的时候从内存读时才更新),这样的话值a就被刷新成更新的b了,保证了多线程多次postValue只有最新的值被更新

结论

LiveData的postValue通过volatile保证了同一个LiveData变量多次调用下也只会更新最新的值,通过阅读liveData的源代码对多线程锁和volatile的使用有了更深的理解。