JetPack之二:LiveData

1.什么是LiveData?

LiveData是一种类,持有可被调查的数据。LiveData是一种可感知生命周期的组件,它是根据lifecycle组件的,意味着该组件注重其他app组件的生命周期,如Activity、Fragment、Service。该组件能确保,仅仅在Activity\Fragment\Service等组件都处于活泼的生命周期状况的时分,才去更新app组件。Activity、Fragment不必担心会出现内存走漏,在Activity、Fragment销毁时,LiveData会主动免除其注册关系。

2.为什么要用Livedata?

  1. LiveData能确保UI和数据状况相符

    由于是调查者形式,LiveData会在生命周期状况改动时,通知调查者 能够在调查者目标中进行UI的更新操作

  2. LiveData没有内存走漏

    调查者和Lifecycle目标绑定,能在销毁时主动免除注册

  3. LiveData不会给已经中止的Activity发送事情

    假设调查者处于非活泼状况,LiveData不会再发送任何事情给这些Observer目标

  4. LiveData能确保不再需求手工对生命周期进行处理

    UI组件仅仅需求对相关数据进行调查 LiveData主动处理生命周期状况改动后,需求处理的代码。

  5. LiveData能确保数据最新

    一个非活泼的组件进入到活泼状况后,会立即获取到最新的数据 不必担心数据问题

  6. LiveData在反正屏切换等Configuration改动时,也能确保获取到最新数据

    例如Acitivty、Fragment由于屏幕选装导致重建, 能立即接收到最新的数据

  7. LiveData能资源共享

    假设将LiveData目标扩大,用单例形式将体系服务进行包裹。这些服务就能够在app中共享。 只需求LiveData和体系服务connect,其他调查者只需求监视LiveData就能获取到这些资源

3.简略运用

首要在你的模块build.gradle里边添加依靠:

dependencies {
  implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
}

最简略的一种运用是MutableLivedata:

class MainActivity : AppCompatActivity() {
​
  private val mLivedata = MutableLiveData<String>()//1
  private val mBinding: ActivityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) }
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(mBinding.root)
    mLivedata.observe(this) {//2
      mBinding.textView.text = it
     }
    var num = 0
    mBinding.button.setOnClickListener {
      mLivedata.value = num++.toString()//3
     }
   }
}

我这儿用了viewbinding代替了findviewbyid。首要在1处定义了mLivedata,类型是MutableLiveData,MutableLiveData是LiveData的子类,露出出了setValue和postValue两个办法。然后在2处订阅,传入的第一个参数是具有生命周期的组件,一般是Activity或许Fragment或许是fragment里边的veiw,第二个参数是收到数据之后的回调,这儿便是用一个textVeiw将值呈现了出来。然后在3处给一个按钮设置监听,每按一次就发送一个数据。大约的用法仍是比较简略的。

再看几个比较进阶的用法:

假设咱们想要在LiveData目标分发给调查者之前对其间存储的值进行更改,能够运用Transformations.map()和Transformations.switchMap()

map()是在数据分发之前进行一些处理,而switchMap更多是在多条LiveData下挑选一条LiveData:

class MainActivity : AppCompatActivity() {
​
  private val mLivedata = MutableLiveData<Int>()
  private val mBinding: ActivityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) }
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(mBinding.root)
    mLivedata.observe(this) {
      mBinding.textView.text = it.toString()
     }
    var num = 0
    mBinding.button.setOnClickListener {
      mLivedata.value = num++
     }
    Transformations.map(mLivedata) {//1
      return@map it - 10000
     }.observe(this) {
      Toast.makeText(this, it.toString(), Toast.LENGTH_SHORT).show()
     }
    Transformations.switchMap(mLivedata) {//2
      val mutableLiveData1 = MutableLiveData<String>()
      val mutableLiveData2 = MutableLiveData<String>()
      mutableLiveData1.value = (it + 10).toString()
      mutableLiveData2.value = (it - 10).toString()
      if (it < 10) return@switchMap mutableLiveData1
      else return@switchMap mutableLiveData2
     }.observe(this) {
      mBinding.textView2.text = it
     }
   }
}

用法很简略,在1处运用Transformations.map对值进行处理,这儿便是对原值减10000,然后observer新的LiveData,这儿便是弹一个吐司。在2处Transformations.switchMap(mLivedata)对原值进行判别,大于10就回来mutableLiveData1,不然mutableLiveData2,然后对新的LiveDataObserver显现在TextView上面。

这两种用法不是很常用。还有一种用法,当有多条LiveData时,咱们需求合并成一条LiveData,这时分能够用MediatorLiveData:

class MainActivity : AppCompatActivity() {
​
  private val mediatorLiveData = MediatorLiveData<Int>()
  private val mutableLiveData1=MutableLiveData<Int>()
  private val mutableLiveData2 = MutableLiveData<Int>()
​
​
  private val mBinding: ActivityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) }
​
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(mBinding.root)
    var num = 0
    mBinding.button.setOnClickListener {
      mutableLiveData1.value = num+20
     }
    mBinding.button2.setOnClickListener {
      mutableLiveData2.value = num-20
     }
    mediatorLiveData.addSource(mutableLiveData1){
      mediatorLiveData.value = it
     }
    mediatorLiveData.addSource(mutableLiveData2){
      mediatorLiveData.value = it
     }
    mediatorLiveData.observe(this){
      mBinding.textView.text = it.toString()
     }
   }
}

首要咱们创建了两条MutableLiveData,然后定义了一个MediatorLiveData,用了两个按钮,分别发送LiveData1和LiveData2的值,再将他们加入到MediatorLiveData,MediatorLiveData本身也是LiveData,再对其Observer这样就达到合并多条LiveData的值。到这儿LiveData的一些简略用法便是这些了。那大家有没有疑问,Activity是怎样感知LiveData发送了值的?LiveData为什么不会形成内存走漏?咱们来看看它的源码,把它扒个精光。

4.原理

首要咱们看LiveData的源码和看LifeCycle的源码相同,从咱们写的代码下手,那便是Observer:

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
  assertMainThread("observe");
  if (owner.getLifecycle().getCurrentState() == DESTROYED) {//1
    // ignore
    return;
   }
  LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);//2
  ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);//3
  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);//4
}

被注解在主线程运转,1处的条件判别阐明咱们在Destroy去Observer是没用的,2处把咱们传进来的owner和observer封装成了LifecycleBoundObserver,它的作用咱们等会分析,3处把wrapper添加进了一个map里边,阐明咱们的liveData是能够有多处Observer的,之后是一些安全判别,最终在4处将咱们的wrapper注册到lifeCycle,这不便是咱们lifeCycle里边学的嘛,那这个LifecycleBoundObserver必定完成了LifeCycleObserver咱们看一看:

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();//1
    if (currentState == DESTROYED) {//2
      removeObserver(mObserver);
      return;
     }
    Lifecycle.State prevState = null;
    while (prevState != currentState) {//3
      prevState = currentState;
      activeStateChanged(shouldBeActive());//4
      currentState = mOwner.getLifecycle().getCurrentState();
     }
   }
​
  @Override
  boolean isAttachedTo(LifecycleOwner owner) {
    return mOwner == owner;
   }
​
  @Override
  void detachObserver() {
    mOwner.getLifecycle().removeObserver(this);
   }
}

果然,完成了LifecycleEventObserver来感知咱们的activity生命周期,那必定在生命周期回调的办法onStateChanged里边做了文章,咱们看,在1处获取了activtiy当时的生命周期状况,2处,处于destroy的话就移除Observer,这阐明了当我 们的activtiy销毁的时分livedata会主动免除监听,所以才不会形成内存走漏。然后在3处判别假设当时状况和即将产生的状况不相同就履行activeStateChanged(shouldBeActive()),那咱们看看shouldBeActive:

@Override
boolean shouldBeActive() {
  return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
public enum State {
    /**
     * Destroyed state for a LifecycleOwner. After this event, this Lifecycle will not dispatch
     * any more events. For instance, for an {@link android.app.Activity}, this state is reached
     * <b>right before</b> Activity's {@link android.app.Activity#onDestroy() onDestroy} call.
     */
    DESTROYED,
​
    /**
     * Initialized state for a LifecycleOwner. For an {@link android.app.Activity}, this is
     * the state when it is constructed but has not received
     * {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} yet.
     */
    INITIALIZED,
​
    /**
     * Created state for a LifecycleOwner. For an {@link android.app.Activity}, this state
     * is reached in two cases:
     * <ul>
     *   <li>after {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} call;
     *   <li><b>right before</b> {@link android.app.Activity#onStop() onStop} call.
     * </ul>
     */
    CREATED,
​
    /**
     * Started state for a LifecycleOwner. For an {@link android.app.Activity}, this state
     * is reached in two cases:
     * <ul>
     *   <li>after {@link android.app.Activity#onStart() onStart} call;
     *   <li><b>right before</b> {@link android.app.Activity#onPause() onPause} call.
     * </ul>
     */
    STARTED,
​
    /**
     * Resumed state for a LifecycleOwner. For an {@link android.app.Activity}, this state
     * is reached after {@link android.app.Activity#onResume() onResume} is called.
     */
    RESUMED;
​
    /**
     * Compares if this State is greater or equal to the given {@code state}.
     *
     * @param state State to compare with
     * @return true if this State is greater or equal to the given {@code state}
     */
    public boolean isAtLeast(@NonNull State state) {
      return compareTo(state) >= 0;
     }
   }

便是将当时状况和START状况相减,大于等于0为true,那也便是START和RSUME这两个状况,LiveData才有效,这也契合用户运用习惯,activtiy也是在START和RSUME呈现页面。

再来看看activeStateChanged():

void activeStateChanged(boolean newActive) {
  if (newActive == mActive) {
    return;
   }
  // immediately set active state, so we'd never dispatch anything to inactive
  // owner
  mActive = newActive;
  changeActiveCounter(mActive ? 1 : -1);
  if (mActive) {
    dispatchingValue(this);
   }
}

首要判别mActive是否和newActive相等,mActive初始状况是不活越的,为flase,所以在newActive为false时也便是activty为不活越的状况就会直接回来而不会直接分发值,之后假设是活泼的状况就changeActiveCounter(mActive ? 1 : -1);改动activeCounter的值,这个咱们用不到,不必管,主要是dispatchingValue,假设是活泼状况就分发值,而且将当时的this传进去,咱们看看:

void dispatchingValue(@Nullable ObserverWrapper initiator) {
  if (mDispatchingValue) {
    mDispatchInvalidated = true;
    return;
   }
  mDispatchingValue = true;
  do {
    mDispatchInvalidated = false;
    if (initiator != null) {//1
      considerNotify(initiator);
      initiator = null;
     } else {//2
      for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
          mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
        considerNotify(iterator.next().getValue());
        if (mDispatchInvalidated) {
          break;
         }
       }
     }
   } while (mDispatchInvalidated);
  mDispatchingValue = false;
}

主要操作鄙人面的do while循环里边,判别咱们传进来的ObserverWrapper是否为空,不为空就履行considerNotify(initiator);为空就循环遍历咱们一开端observer里边添加的observerWrapper,为什么是for循环?由于咱们刚才说了,一个liveData能够被多个生命周期组件观测。所以在这儿为null的时分从Observers这个map里边去拿。咱们看看considerNotify(initiator);

private void considerNotify(ObserverWrapper observer) {
  if (!observer.mActive) {//1
    return;
   }
  // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
  //
  // we still first check observer.active to keep it as the entrance for events. So even if
  // the observer moved to an active state, if we've not received that event, we better not
  // notify for a more predictable notification order.
  if (!observer.shouldBeActive()) {//2
    observer.activeStateChanged(false);
    return;
   }
  if (observer.mLastVersion >= mVersion) {//3
    return;
   }
  observer.mLastVersion = mVersion;
  observer.mObserver.onChanged((T) mData);
}

在1处判别,不活越就直接结束。在2处是一些边界处理,上面的注释也说了当activty生命周期改动时,还未来的及改动mActive的值,此刻应该先更改活泼的状况再分发值,这其实不重要咱们一般碰不到。然后在3处判别前次的version是否比当时的mVersion大,不然再鄙人面更新mLastVersion,而且履行onChange,也便是咱们再observer办法里边传进来的lamda表达式。一开端mLastVersion和mVersion都是为-1的,所以不会履行下面的回调。到这儿Observer办法咱们从始至终理解了一边。那一开端咱们的onChanged不会回调,那什么时分会呢?答案在setValue里边,咱们看一看:

@MainThread
protected void setValue(T value) {
  assertMainThread("setValue");
  mVersion++;
  mData = value;
  dispatchingValue(null);
}

注解阐明,setValue是在主线程履行,然后mVersion++;由于一开端mVersion是等于mLastVersion的,现在++了,必定比mLastVersion大,之后dispatchingValue(null),注意看,这时分传入的值为null,也便是咱们刚刚说的dispatchingValue传入值为null的时分会for遍历所有的Oberver然后considerNotify,也就到了:

private void considerNotify(ObserverWrapper observer) {
  if (!observer.mActive) {
    return;
   }
  // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
  //
  // we still first check observer.active to keep it as the entrance for events. So even if
  // the observer moved to an active state, if we've not received that event, we better not
  // notify for a more predictable notification order.
  if (!observer.shouldBeActive()) {
    observer.activeStateChanged(false);
    return;
   }
  if (observer.mLastVersion >= mVersion) {
    return;
   }
  observer.mLastVersion = mVersion;
  observer.mObserver.onChanged((T) mData);
}

这时分mVsersion小于mLastVersion,所以便是会履行onChanged,也便是咱们传进来的lamda表达式,这就说清楚了为什么每次setValue,activity都能收到值得原因啦。那咱们再看看liveData的另外一个办法,postValue:

protected void postValue(T value) {
  boolean postTask;
  synchronized (mDataLock) {
    postTask = mPendingData == NOT_SET;//1
    mPendingData = value;//2
   }
  if (!postTask) {
    return;
   }
  ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);//3
}
private final Runnable mPostValueRunnable = new Runnable() {
    @SuppressWarnings("unchecked")
    @Override
    public void run() {
      Object newValue;
      synchronized (mDataLock) {
        newValue = mPendingData;
        mPendingData = NOT_SET;
       }
      setValue((T) newValue);//4
     }
 };

postValue是用来在子线程向liveData发送值的,首要判别mPendingData的值是不是还没设置过,是的话才会分发值,而且将value赋给mPendingData,然后将mPostValueRunnable扔到主线程运转,mPostValueRunnable里边把mPendingData赋值给newValue,再将mPendingData置为未设置,最终履行的便是setValue;其实postToMainThread也便是用Handler发送一个消息到主线程:

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

那你们有没有发现一个问题,已然setValue是用Handler发一个消息到主线程,而Handler消息是个队列,那假设我同时postValue屡次,但由于前面的消息还没处理完,mPostValueRunnable还没有运转,mPendingData还没有被置为NOT_SET,postTask就一向为false,所以后面的postValue直接return了,形成我中心postValue的值直接被覆盖了,从而只收到了最新postValue的值,形成了中心值丢失的问题。解决问题很简略,自己切换到主线程然后用setValue,setValue是不会丢值得。

至此,LiveData的源码分析的差不多了,至于liveData的其他什么办法比如说,observerForever,rmoveobserverForever,都比较简略了,而且也不常用,相信你把这些根底的搞懂,其他的不会太难理解。

LiveData数据倒灌

数据倒灌简而言之便是咱们并没有给livedata设置数据而收到了旧的数据。

LiveData的数据倒灌问题。便是当咱们用LiveData去发送数据产生事情的时分,你会发现事情会屡次产生。咱们知道咱们的LiveData是在onCreate去Observe的,而且经过源码咱们知道,Observer的时分内部会new 一个LifecycleBoundObserver,而且将observe.mLastVersion置为默认值-1,可是此刻LiveData的mVersion是没有改动的。而咱们的LiveData一般是放在viewmoodel中的,liveData必定比Activity活的时间长,假设咱们在onCreate里去Observe而且给LiveData发送数据,在此过后mVersion是++了的也便是说mVersion至少是大于初始值-1的,假设此刻Activtiy重建,重走onCreate办法,此刻mVersion是保存在LiveData里边,LiveData是在viewmodel里边,LiveData的实例没有被重建,可是从头走了onCreate,从头Observe了,又从头new了一个LifecycleBoundObserver,也便是mLastVersion为-1,所以此刻mLastVersion<mVersion,会回调咱们的onChanged()。这便是为什么用LiveData发送事情会被消费屡次。而数据多贴一遍咱们也不会觉得有问题。可是这其实也不是LiveData的一个bug,liveData规划理念便是专注于给UI层发送数据,关于事情这种咱们更应该运用flow或许rxjava。可是把LiveData改改也能用:

class SingleLiveData<T> : MutableLiveData<T>() {
  private val mPending = AtomicBoolean(false)
​
  @MainThread
  override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
    if (hasActiveObservers()) {
      Log.w(
        "SingleLiveEvent",
        "Multiple observers registered but only one will be notified of changes."
       )
     }
    super.observe(owner) { t ->
      if (mPending.compareAndSet(true, false)) {
        observer.onChanged(t)
       }
     }
   }
​
  @MainThread
  override fun setValue(t: T?) {
    mPending.set(true)
    super.setValue(t)
   }
​
  @MainThread
  fun call() {
    value = null
​
   }
}

AtomicBoolean是经过原子方式更新 boolean 值,能够确保线程安全。这也是官方Demo里边的解决方案,用个boolean记载一次value是否被消费。一次setValue对应一次onChanged而且这个Boolean值是保存在LiveData中的,这样就能用于发送事情了。

其实最佳的解决方案便是不要用LiveData去发送“事情”。

好了以上便是LiveData的一些介绍,喜爱的点点关注点点赞哟。