美文网首页
LiveData介绍

LiveData介绍

作者: 大虾啊啊啊 | 来源:发表于2022-02-22 15:35 被阅读0次

1、简介

同时具有观察者身份和被观察者身份的组件、LiveData数据的改变,可以监听到其的变化。用数据驱动的思想替换了常规接口回调的方式。

2、使用

  • 简单的使用
    (1)创建一个LiveData
/**
 *   author : weishixiong
 *   e-mail : weishixiong@pudutech.com
 *   date   : 2022/2/22 10:48
 *   desc   :单例MyLiveData
 */
object MyLiveData {
    val data = MutableLiveData<String>()
}

(2)改变并监听其数据的变化

class MainActivity : AppCompatActivity() {
    val TAG = javaClass.simpleName
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        MyLiveData.data.observe(this, object : Observer<String> {
            override fun onChanged(t: String?) {
                Log.e(TAG, "onChanged:${Thread.currentThread().name} and  ${t}")
            }

        })
        MyLiveData.data.postValue("hello world")

class MainActivity : AppCompatActivity() {
    val TAG = javaClass.simpleName
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        MyLiveData.data.observe(this, object : Observer<String> {
            override fun onChanged(t: String?) {
                Log.e(TAG, "onChanged:${Thread.currentThread().name} and  ${t}")
            }
        })
        MyLiveData.data.value = "hello "
        thread {
            MyLiveData.data.postValue("world")
        }
    }
}
com.example.lifecycle E/MainActivity: onChanged:main and  hello 
com.example.lifecycle E/MainActivity: onChanged:main and  world
  • setValue和postValue的区别

(1)setValue只能在主线程调用
(2)postValue既能在主线程调用,也能在子线程调用,如果需要在子线程调用改变LiveData的数据,使用postValue
(3)postValue最终也是调用到setValue方法,通过Handler线程切换到主线程,然后在主线程调用setValue
如下源码体现:
调用postValue方法,在postValue方法中调用postToMainThread方法

    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

在postToMainThread方法中,拿到主线程的Looper设置给Handler,在调用 mMainHandler.post(runnable);

   @Override
    public void postToMainThread(Runnable runnable) {
        if (mMainHandler == null) {
            synchronized (mLock) {
                if (mMainHandler == null) {
                    mMainHandler = new Handler(Looper.getMainLooper());
                }
            }
        }
        //noinspection ConstantConditions
        mMainHandler.post(runnable);
    }

在Runnable中执行setValue方法

   private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            setValue((T) newValue);
        }
    }
  • LiveData的粘性事件
    通常在使用LiveData的使用,我们都是先调用observe方法订阅,然后再改变数据。
    但是假如我们先改变数据,然后再订阅,其实也是能收到数据的变化,这种现象称之为粘性事件,这并不是一个BUG,而是LiveData的特性。
    例如:我们再MainActivity1中先对LiveData的值进行改变,然后再跳转到MainActivity2订阅LiveData,来看看现象
        MyLiveData.data.value = "hello world"
        findViewById<TextView>(R.id.tv_click).setOnClickListener {
            startActivity(Intent(this, Main2Activity::class.java))
        }
class Main2Activity : AppCompatActivity() {
    val TAG = javaClass.simpleName
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        MyLiveData.data.observe(this, object : Observer<String> {
            override fun onChanged(t: String?) {
                Log.e(TAG, "onChanged:${Thread.currentThread().name} and  ${t}")
            }
        })
    }
}
Main2Activity: onChanged:main and  hello world

我们看到在Main2Activity 依然能收到LiveData变化之后的数据。在后面源码分析我们将分析为什么?

3、源码简单分析

  • LiveData的注册
    调用LiveData的observe进行注册,并传入当前Activity的实例this,和Observe的实现类,重写onChanged函数
  MyLiveData.data.observe(this, object : Observer<String> {
            override fun onChanged(t: String?) {
                Log.e(TAG, "onChanged:${Thread.currentThread().name} and  ${t}")
            }
        })

在observe方法中,首先将我们的宿主和observer包装成一个LifecycleBoundObserver,而LifecycleBoundObserver实现了LifecycleEventObserver接口并继承了ObserverWrapper类,这样一来LifecycleBoundObserver就可以监听宿主Activity的生命周期并持有了observer对象。

@MainThread
   public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
       assertMainThread("observe");
       if (owner.getLifecycle().getCurrentState() == DESTROYED) {
           return;
       }
     //创建LifecycleBoundObserver  监听宿主的生命周期,并持有observer对象
       LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
   //同时将LifecycleBoundObserver存入到一个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;
       }
       owner.getLifecycle().addObserver(wrapper);
   }

同时调用了putIfAbsent 将LifecycleBoundObserver 对象存到一个map中。然后调用addObserver,将LifecycleBoundObserver 关联到宿主Activity中,监听其生命周期。
以上代码小结:LiveData调用observe方法注册的时候,主要做了两个工作
(1)创建一个LifecycleBoundObserver对象,并持有observer。监听宿主Activity的生命周期
(2)将LifecycleBoundObserver存到一个map中

  • 设置LiveData的数据
    通过使用setValue和postValue方法设置LiveData的数据,最终都会调用到setValue这话方法,
@MainThread
  protected void setValue(T value) {
      assertMainThread("setValue");
      mVersion++;
      mData = value;
      dispatchingValue(null);
  }

在setValue方法中对mVersion成员变量+1,这个变量很关键,通过这个变量来判断LiveData数据是否改变了。然后再setValue方法中调用dispatchingValue方法,意思就是将改变之后的数据分发出去。dispatchingValue方法如下:

  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;
    }

由于dispatchingValue方法传的参数为null,所有会走到else中去,接着遍历之前存到map中的LifecycleBoundObserver对象,调用considerNotify函数

@SuppressWarnings("unchecked")
    private void considerNotify(ObserverWrapper observer) {
    //判断是否可见
        if (!observer.mActive) {
            return;
        }
    //判断是否可见
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }

然后回调observer中的onChanged方法。而在调用onChanged方法之前主要做了两个判断:
(1)通过LifecycleBoundObserver监听Activity的生命周期,调用shouldBeActive函数和mActive属性,判断Activity是否可见,如果不可见直接return,所以当我们的Activity是不可见的时候,是监听不到数据的变化的。
如果需要不可见的时候也监听数据的变化可以采用observeForever
(2)判断LifecycleBoundObserver中持有的版本mLastVersion 是否小于LiveData的版本,如果小于,所以mVersion有做过++,因为我们在setValue的时候,有对mVersion+1操作。
在初始化的时候mVersion和mLastVersion的版本都为-1。当mVersion+1之后,mVersion版本>LifecycleBoundObserver中mLastVersion 的版本。说明有数据改变,所以直接回调onChanged函数。接着对齐版本,将mVersion的值,赋值给mLastVersion。
在上面我们可以看到主要通过dispatchingValue这个函数,将数据分发出去,然后回调我们的onChanged函数
那为什么数据会粘性呢?
我们来观察调用dispatchingValue的地方,除了LiveData设置数据的时候主动触发,同时在Activity生命周期变化的时候,也会触发。我们来看下代码

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);
     }
     @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
     boolean isAttachedTo(LifecycleOwner owner) {
         return mOwner == owner;
     }
     @Override
     void detachObserver() {
         mOwner.getLifecycle().removeObserver(this);
     }
 }
 private abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        boolean mActive;
        int mLastVersion = START_VERSION;

        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;
            changeActiveCounter(mActive ? 1 : -1);
            if (mActive) {
                dispatchingValue(this);
            }
        }
    }

我们看到LifecycleBoundObserver 通过onStateChanged函数监听宿主Activity的生命周期,然后调用ObserverWrapper 中的activeStateChanged方法,在activeStateChanged方法中调用dispatchingValue分发数据。此时dispatchingValue方法的传参,传了this。也就是LifecycleBoundObserver 对象。

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;
    }

这样就触发dispatchingValue方法中的if部分,调用 considerNotify(initiator);在considerNotify中的操作就一样了,同样是先判断版本,如果当前版本大于LifecycleBoundObserver 中的版本,就回调onChanged函数。
而由于在调用MainActivity1中调用setValue的时候,我们将mVersion++,所以mVersion的版本是>mLastVersion的。所以就会回调onChanged,MainActivity2就能收到LiveData数据的变化,这样就被称为了粘性事件。

private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }
  • 通过一张图大概分析LiveData的工作原理
image.png

总结

  • LiveData不管是通过post还是set,最终都是通过setValue改变数据
  • LiveData监听数据的变化主要通过当前版本mVersion和LifecycleBoundObserver 持有的版本进行比较。
  • LiveData持有了一个LifecycleBoundObserver 对象,主要是用于监听Activity的生命周期,持有一个observer作为观察者,观察LiveData的数据变化。变化的时候通过observer的onChanged函数
  • 触发onChanged方法,也就是监听到数据变化的时候,主要有两个途径
    (1)当调用LiveData的setValue方法的时候mVersion+1,然后主动去回调observer的onChanged方法,回调该方法之前判断版本和Activity是否可见,都满足的时候才调用。如果不满足,直接rerurn,不做处理。
    (2)当LifecycleBoundObserver 监听到Activity生命周期为可见的时候,同样按照上述步骤1判断版本号,决定是否回调onChanged方法。这也是粘性数据的根本原因,如果启动第二个Activity的时候,发现版本大于LifecycleBoundObserver 持有的版本,则说明数据有变化。回调onChanged方法

相关文章

网友评论

      本文标题:LiveData介绍

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