• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Jetpack四—— LiveData

武飞扬头像
橙子19911016
帮助1

1 简介

以下是LiveData的官网定义:LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services.

从官网的介绍可以看到,LiveData作用跟RxJava类似,是观察数据的类,相比RxJava,它能够在ActivityFragmentService之中正确的处理生命周期。 乍看之下,LiveData挺鸡肋的,事实也确实如此,因为LiveData能够实现的功能RxJava也可以实现,而且与LiveData相比, RxJava拥有着更加丰富的生态,当然,谷歌的官方架构仍然值得我们去学习。

LiveData是一种可观察的数据存储器类,它可以包含任何类型的数据。与常规的可观察类不同,LiveData具有生命周期感知能力,意思是它遵循其它应用组件(如 ActivityFragmentService)的生命周期。这种感知能力可确保LiveData仅更新处于活跃生命周期状态的(应用组件)观察者。

如果观察者的生命周期处于STARTEDRESUMED状态,则LiveData会认为该观察者处于活跃状态。LiveData 只会将更新通知给活跃的观察者,而非活跃观察者不会收到更改通知。 因此,可以在实现LifecycleOwner接口的类中注册观察者,当相应的Lifecycle对象的状态变为DESTROYED时,便可移除此观察者。 这对于ActivityFragment特别有用,这样它们就可以放心地观察LiveData对象,而不必担心内存泄露(当ActivityFragment的生命周期结束时,系统会立即退订它们)。

使用LiveData具有以下优势:

  • 数据变更的时候更新UI LiveData遵循观察者模式,当数据发生变化时,LiveData会通知Observer对象,可以在这些 Observer 对象中更新界面,无需在每次应用数据发生变化时更新界面,因为观察者会完成更新;
  • 不会发生内存泄漏。 观察者会绑定到Lifecycle对象,并在其关联的生命周期遭到销毁后进行自我清理;
  • 不会因Activity停止而导致崩溃。 如果观察者的生命周期处于非活跃状态(如返回栈中的Activity),它不会接收任何 LiveData事件;
  • 不再需要手动处理生命周期。 界面组件只是观察相关数据,不会停止或恢复观察。LiveData将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化;
  • 数据始终保持最新状态。 如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的Activity会在返回前台后立即接收最新的数据;
  • 适当的配置更改。 如果由于配置更改(如设备旋转)而重新创建了ActivityFragment,它会立即接收最新的可用数据;
  • 共享资源。 可以使用单例模式扩展LiveData对象以封装系统服务,以便在应用中共享它们。LiveData 对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察 LiveData 对象;

LiveData经常与ViewModel在一起使用,虽然它也可以单独用在别的地方,但是在绝大多数情况下,它是使用在ViewModel当中的。

学新通

LiveDataViewModel在整个MVVM架构中担当数据驱动的职责,这也是MVVM模式中ViewModel层的作用。

为什么不把Activity的实例传给ViewModel呢,这样ViewModel不就能主动对Activity进行通知了吗?这是因为ViewModel的生命周期是长于Activity的,如果把Activity的实例传给ViewModel,就很有可能会因为Activity无法释放而造成内存泄漏,这是一种非常错误的做法。

2 LiveData的基本用法

  1. 创建 LiveData 的实例用来存储某种类型的数据,通常在ViewModel类中完成;
  2. 创建可定义onChanged()方法的Observer对象,该方法可以控制 LiveData 对象存储的数据更改时会发生什么。通常情况下,可以在界面控制器(如ActivityFragment)中创建 Observer 对象;
  3. 使用observe()方法将 Observer 对象附加到 LiveData 对象,observe() 方法会采用LifecycleOwner对象,这样会使 Observer 对象订阅 LiveData 对象,以使其收到有关更改的通知。通常情况下,可以在界面控制器(如ActivityFragment)中附加 Observer 对象;

注意:可以使用observeForever(Observer)方法在没有关联的LifecycleOwner对象的情况下注册一个观察者。在这种情况下,观察者会被视为始终处于活跃状态,因此它始终会收到关于修改的通知。可以通过调用removeObserver(Observer)方法来移除观察者。

它的使用是首先使用LiveData来存储某种类型的数据,这个过程一般是在ViewModel中完成,之后创建Observer对象,Observer接口中只有一个方法onChange(T t),当数据发生变化时就会调用这个方法,一般是在组件,如Activity/Fragment中创建观察者对象;之后调用数据类的observe方法,添加LifecycleOwner对象和observer,这样就可以观察数据的变化了。

当更新存储在 LiveData 对象中的值时,它会触发所有已注册的观察者(只要附加的 LifecycleOwner 处于活跃状态)。LiveData允许界面控制器观察者订阅更新。当LiveData 对象存储的数据发生更改时,界面会自动更新以做出响应。

lifecycle-livedata-ktx就是一个专门为Kotlin语言设计的库,这个库在2.2.0版本中加入了对observe()方法的语法扩展。 我们只需要在app/build.gradle文件中添加如下依赖:

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

2.1 创建LiveData对象

LiveData是一种可用于任何数据类型的封装容器,其中包括可实现 Collections 的对象,如ListLiveData对象通常存储在ViewModel对象中,并可通过getter方法进行访问, 如以下示例中所示:

class NameViewModel : ViewModel() {
    // create a LiveData with a String
    val currentName: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }
    
    // Rest of the ViewModel
}

注意:请确保用于更新界面的 LiveData 对象存储在 ViewModel 对象中,而不是将其存储在ActivityFragment中,原因如下:避免 ActivityFragment过于庞大。现在,这些界面控制器负责显示数据,但不负责存储数据状态。将 LiveData 实例与特定的ActivityFragment实例分离开,并使 LiveData 对象在配置更改后继续存在。

LiveData常用方法:

学新通

MutableLiveData是一种可变的LiveData,它的用法很简单,主要有3种读写数据的方法,分别是getValue()setValue()postValue()方法:

  • getValue()方法用于获取LiveData中包含的数据;
  • setValue()方法用于给LiveData设置数据,但是只能在主线程中调用;
  • postValue()方法用于在非主线程中给LiveData设置数据;

以下是MutableLiveDataLiveData的源码:

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

public abstract class LiveData<T> {
  
}

2.2 观察LiveData对象

在大多数情况下,应用组件的 onCreate() 方法是开始观察LiveData对象的正确着手点,原因如下:

  • 确保系统不会从ActivityFragmentonResume() 方法进行冗余调用;
  • 确保ActivityFragment变为活跃状态后具有可以立即显示的数据。一旦应用组件处于STARTED状态,就会从它正在观察的 LiveData 对象接收最新值。只有在设置了要观察的 LiveData 对象时,才会发生这种情况;

通常,LiveData仅在数据发生更改时才发送更新,并且仅发送给活跃观察者。此行为的一种例外情况是,观察者从非活跃状态更改为活跃状态时也会收到更新。此外,如果观察者第二次从非活跃状态更改为活跃状态,则只有在自上次变为活跃状态以来值发生了更改时,它才会收到更新。

以下示例代码说明了如何开始观察 LiveData 对象:

class NameActivity : AppCompatActivity() {

    private val model: NameViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_name)

        // Other code to setup the activity

        // Create the observer which updates the UI.
        val nameObserver = Observer<String> { newName ->
            // Update the UI, in this case, a TextView.
            nameTextView.text = newName
        }

        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer
        model.currentName.observe(this, nameObserver)
    }
}
学新通

通过调用model.currentName.observe方法来观察数据的变化。任何LiveData对象都可以调用它的observe()方法来观察数据的变化。observe()方法接收两 个参数:第一个参数是一个LifecycleOwner对象,Activity本身就是一个LifecycleOwner对象,因此直接传this就好;第二个参数是一个Observer接口, 当currentName中包含的数据发生变化时,会立即调用Observer.onChanged方法。

以下是Observer的源码:

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

另外,关于LiveData.observe()方法,observe()方法是一个Java方法,如果观察Observer接口,会发现这是一个单抽象方法接口,只有一个待实现的onChanged()方法。因此也可以写成:

model.currentName.observe(this) { newName ->
      nameTextView.text = newName
}

2.3 更新 LiveData 对象

LiveData没有公开可用的方法来更新存储的数据。MutableLiveData类将公开setValue(T)postValue(T)方法,如果需要修改存储在LiveData对象中的值,则必须使用这些方法。通常情况下会在ViewModel中使用 MutableLiveData,然后 ViewModel 只会向观察者公开不可变的 LiveData 对象。

设置观察者关系后,可以更新 LiveData 对象的值(如以下示例中所示),这样当用户点按某个按钮时会触发所有观察者:

button.setOnClickListener {
  val anotherName = "John Doe"
  model.currentName.value = anotherName
}

在本示例中调用 setValue(T) 导致观察者使用值 John Doe 调用其onChanged()方法。本示例中演示的是按下按钮的方法,但也可以出于各种各样的原因调用 setValue()postValue() 来更新 mName,这些原因包括响应网络请求或数据库加载完成。在所有情况下,调用 setValue()postValue() 都会触发观察者并更新界面。

注意:必须调用setValue(T)方法以从主线程更新 LiveData 对象。如果在工作器线程中执行代码,可以改用postValue(T)方法来更新 LiveData 对象。

3 LiveData的源码分析

3.1 LiveData.observe(LifecyleOwner owner, Observer<? super T> observer)

obsever方法中传入了两个参数,一个是LifecycleOwner,一个是Observer。**Observer是观察者,它是一个单一方法接口,当数据发生变化时,会回调onChange(T t)方法,**以下是相关源码:

public interface Observer<T> {
      /**
       * Called when the data is changed.
       * @param t  The new data
       */
      void onChanged(T t);
}

之后来看observe方法的具体实现,以下是源码:

public abstract class LiveData<T> {
  
  private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();

    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
      	// 1. 只能在主线程中调用observe方法
        assertMainThread("observe");
        // 	2. 当Lifecycle.State == DESTROYED时,订阅观察者时没有意义的,直接返回
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
          return;
        }
      	// 3. LifeycleBoundObserver最终是LifecycleObserver的实现类
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
      	// 4. observer作为key,wrapper作为值进行存储(observer-wrapper)。pubIfAbsent表示如果observers中已经有observer,则返回observer对应的值;如果没有,则返回null
        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;
        }
      	// 5. 获取Lifecycle,并为它添加观察者
        owner.getLifecycle().addObserver(wrapper);
    }

}
学新通

LiveData.observer方法中,首先保证了在主线程中进行,然后判断当前的Lifecycle.State是否是处于DESTROYED状态下的,如果是,则不再进行订阅,注释1,注释2

之后的流程就是为Lifecycle添加观察者的过程。首先要创建观察者,从注释5处可以知道wrapper就是观察者对象,所以这个类一定是LifecycleObserver的实现类,以下是LifecycleBoundObserver继承和实现关系:

public abstract class LiveData<T> {

    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
       
    }
}

从源码中给可以知道LifecycleBoundObserver继承了抽象类ObserverWrapper,实现了LifecycleEventObserver,以下是LifecycleEventObserver的相关源码:

public interface LifecycleEventObserver extends LifecycleObserver {
    /**
     * Called when a state transition event happens.
     *
     * @param source The source of the event
     * @param event The event
     */
    void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
}

public interface LifecycleObserver {

}

LifecycleEventObserver实现了LifecycleObserver接口,并且其内部只有一个onStateChange方法,在状态转换事件事件发生的时候调用。因此,LifecycleBoundObserver作为LifecycleObserver的实现类,可以作为参数传递给Lifecycle.addObserver(LifecycleObserver)

以下是LifecycleBoundObserver的相关源码:

public abstract class LiveData<T> {

    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }

      	// 6 判断观察者是否处于活跃状态(STATED、RESUMED)(重写自ObserverWrapper的抽象方法)
        @Override
        boolean shouldBeActive() {
          	return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

      	// 7 实现LifecycleEventObsever的接口方法,在状态转换事件事件发生的时候调用
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
           	// 8 在生命周期状态为DESTROYED时,取消订阅。这也是LiveData数据不需要主动取消订阅的原因,因为这里已经帮它取消了
            if (currentState == DESTROYED) {
              removeObserver(mObserver);
              return;
            }
            Lifecycle.State prevState = null;
            while (prevState != currentState) {
              prevState = currentState;
              // 9 ObserverWrapper中的方法,参数:当前是否是活跃状态
              activeStateChanged(shouldBeActive());
              currentState = mOwner.getLifecycle().getCurrentState();
            }
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
          	return mOwner == owner;
        }

        @Override
        void detachObserver() {
          	mOwner.getLifecycle().removeObserver(this);
        }
    }
}
学新通

再看ObserverWrapper的源码:

public abstract class LiveData<T> {
  
  	static final int START_VERSION = -1;

    private abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        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() {
        }
      	
      	// 10. newActive:是否是活跃状态
        void activeStateChanged(boolean newActive) {
         		// 11. mActive的初始值为null,所以首次调用的时候newActive != mActive
            if (newActive == mActive) {
              return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
          	// 12. mActive被赋予了newActive的值。因此,通过11处的判断可以知道,只有在newActive发生变化的时候才会走之后的逻辑,这种变化包括:活跃 -> 不活跃;不活跃 -> 活跃
            mActive = newActive;
          	
            changeActiveCounter(mActive ? 1 : -1);
          	// 12 如果观察者处于活跃状态,则进行数据分发
            if (mActive) {
              dispatchingValue(this);
            }
      }
}
学新通

由以上源码可知,只有在活跃状态下,才会进行分发。以下是dispatchingValue的相关源码:

public abstract class LiveData<T> {
  
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) { // 正在分发
          mDispatchInvalidated = true;
          return;
        }
        mDispatchingValue = true; // 标记正在分发
        do {
          mDispatchInvalidated = false;
          // 13 此时的initial不为空
          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;
        }
        // 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;
        // 14 最终调用了Observer.onChange(T t)方法
        observer.mObserver.onChanged((T) mData);
    } 
}
学新通

3.2 LiveData.observeForever(Observer<? super T> observer)

public abstract class LiveData<T> {
    @MainThread
    public void observeForever(@NonNull Observer<? super T> observer) {
        assertMainThread("observeForever");
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing instanceof LiveData.LifecycleBoundObserver) {
          throw new IllegalArgumentException("Cannot add the same observer"
                      " with different lifecycles");
        }
        if (existing != null) {
          return;
        }
        wrapper.activeStateChanged(true);
    }
  
    private class AlwaysActiveObserver extends ObserverWrapper {

        AlwaysActiveObserver(Observer<? super T> observer) {
          super(observer);
        }

        @Override
        boolean shouldBeActive() {
          return true;
        }
    }

    static void assertMainThread(String methodName) {
        if (!ArchTaskExecutor.getInstance().isMainThread()) {
          throw new IllegalStateException("Cannot invoke "   methodName   " on a background"
                                            " thread");
        }
    }
}
学新通

这里有一个类AlwaysActiveObserver也是ObserverWrapper的子类,与LifecycleBoundObserver不同的是,它的方法shouldBeActive总是返回trueactiveStateChange(true)方法的参数也是固定的true,所以这个方法是不依赖生命周期状态的。在使用完observeForever函数后,一定要主动移除Observer,避免内存泄露和空指针异常。

3.3 LiveData.postValue(T value)/LiveData.setValue(T value)

public abstract class LiveData<T> {

  	// 子线程中调用
    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
          postTask = mPendingData == NOT_SET;
          mPendingData = value;
        }
        if (!postTask) {
          return;
        }
      	// 线程切换
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
  
  	private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
          Object newValue;
          synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
          }
          // 1. 最终还是使用setValue实现
          setValue((T) newValue);
        }
    };

  	// 主线中调用
    @MainThread
    protected void setValue(T value) {
      	// 检查当前是否在主线程
        assertMainThread("setValue");
        mVersion  ;
        mData = value;
        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 {
            // 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;
    }
  
    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;
          // 3 最终调用了Observer.onChange(T t)方法
          observer.mObserver.onChanged((T) mData);
      } 

}
学新通

4 黏性事件/数据倒灌

val liveDate = MutableLiveData<String>()
liveDate.value = "1111"

button.setOnClickListener {
  liveDate.observe(this) {
    Log.e("CAH", "liveData.value: $it")
  }
}

// CAH: liveData.value: 1111

按照正常的逻辑,在订阅观察者之后,才能收到被观察者发送的消息。那么,为什么在LiveData有值后,调用LiveData.observe订阅观察者,还是会收到旧值?这就是粘性事件。EventBus也存在黏性事件的场景。

LiveData的源码中可以知道,只有在considerNotify(ObserverWrapper observer)方法中调用了observer.mObserver.onChanged(T t)方法。调用considerNotify(Observer observer)的方法只有有dispatchingValue(ObserverWrapper initiator),而调用dispatchingValue(ObserverWrapper initiator)方法有setValue(T value)ObserverWrapper.activeStateChanged(boolean newActive),因为此时没有进行数据的变动,所以走的是ObserverWrapper.activeStateChanged(boolean newActive)方法。而调用ObserverWrapper.activeStateChanged(boolean newActive)LifecycleBoundObserver.onStateChanged(LifecycleOwner source, Lifecycle.Event event),而这个方法被回调说明,和生命周期状态变化相关的事件发生了变化。这就涉及到了Lifecyle.addObserver(Observer observer)方法中的生命周期状态对齐。初始的观察者的生命周期都是INITIALIZED,通过while循环和当前的生命周期状态对齐。

学新通

通过以下代码来测试一下:

button.setOnClickListener {
    lifecycle.addObserver(object : LifecycleObserver {
        @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
        private fun create() {
          Log.e("CAH", "create")
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_START)
        fun start() {
          Log.e("CAH", "start")
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
        fun resume() {
          Log.e("CAH", "resume")
        }
    })
  
}

// CAH: create
// CAH: start
// CAH: resume

// 或者使用LifecycleEventObserver
playerOrPauseBtn.setOnClickListener {
  lifecycle.addObserver(object : LifecycleEventObserver {
    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
      Log.e("CAH", "onStateChanged: ${event.name}")
    }
  })
}

// CAH: onStateChanged: ON_CREATE
// CAH: onStateChanged: ON_START
// CAH: onStateChanged: ON_RESUME
学新通

由此可以知道生命周期的状态一定发生了变化,也就一定调用了onStateChanged(LifecycleOwner source, Lifecycle.Event event)这个方法。那为什么Observer.onChanged(T t)方法只调用了一次,以下是considerNotify(ObserverWrapper observer)方法的源码:

public abstract class LiveData<T> {
  
  private int mVersion;
  
  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;
      // 3 最终调用了Observer.onChange(T t)方法
      observer.mObserver.onChanged((T) mData);
  } 

}
学新通

这里有一个版本号机制,当被调用一次后,observer.mLastVersion == mVersion,因此就不会再执行后面的逻辑了。

通过上面的分析,只要数据设定值,即便是之后订阅的观察者,也会接收到数据的值,这就是粘性事件。这也是为什么通常使用LiveData时,在应用组件的onCreate()方法中就要订阅观察者,就是为了避免粘性事件的发生。

目前解决粘性事件的方案有很多,这里只说一种,那就是通过反射干预Version值的方式。根据之前的分析,只需要在LiveData绑定LifecycleOwner的时候把ObserverWrappermLastVersion设置成跟LiveData.version一致即可。

5 转换LiveData

如果希望在LiveData对象分派给观察者之前对存储在其中的值进行更改,或者需要根据另一个实例的值返回不同的 LiveData 实例,Lifecycle软件包提供Transformations类,提供了可应对这些情况的方法。

5.1 Transformations.map()

map()方法的作用是将实际包含数据的LiveData和仅用于观察数据的LiveData进行转换。

举一个例子,比如说有一个User类,User中包含用户的姓名和年龄,定义如下:

data class User(var name: String, var lastName: String, var age: Int)

可以在ViewModel中创建一个相应的LiveData来包含User类型的数据,如下所示:

val userLiveData: LiveData<User> = UserLiveData()

如果Activity中只显示用户的姓名,而不关心用户的年龄,这个时候还将整个User类型的LiveData暴露给外部,就显得不那么合适了。map()方法就是专门用于解决这种问题的,它可以将User类型的LiveData自由地转型成任意其他类型的LiveData

val userName: LiveData<String> = Transformations.map(userLiveData) {
    user -> "${user.name} ${user.lastName}"
}

可以看到,这里调用了Transformations.map()方法来对LiveData的数据类型进行转换。map()方法接收两个参数:第一个参数是原始的LiveData对象;第二个参数是一个转换函数,在转换函数里编写具体的转换逻辑即可。 这里的逻辑也很简单,就是将User对象转换成一个只包含用户姓名的字符串。

另外,还将userLiveData声明成了private,以保证数据的封装性。外部使用的时候只要观察userName这个LiveData就可以了。当userLiveData的数据发生变化时,map()方法会监听到变化并执行转换函数中的逻辑,然后再将转换之后的数据通知给userName的观察者。

5.2 Transformations.switchMap()

在之前的例子中,有个前提:LiveData对象的实例都是在ViewModel中创建的,然而在实际的项目中,不可能一直是这种理想情况,很有可能ViewModel中的某个LiveData对象是调用其它类的方法获取的。下面模拟一下这种情况,新建一个Repository单例类,代码如下所示:

object Repository {
    fun getUser(userId: String): LiveData<User> {
        val liveData = MutableLiveData<User>()
        ...
        liveData.value = User(name, lastName, 10)
        return liveData
    }
}

这里在Repository类中添加了一个getUser()方法,这个方法接收一个userId参数。 按照正常的编程逻辑,应该根据传入的userId参数去服务器请求或者到数据库中查找相应的User对象。需要注意的是,getUser()方法返回的是一个包含User数据的LiveData对象,而且每次调用getUser()方法都会返回一个新的LiveData实例。

然后在ViewModel中也定义一个getUser()方法,并且让它调用RepositorygetUser()方法来获取LiveData对象:

fun getUser(userId: String): LiveData<User> {
    return Repository.getUser(userId)
}

接下来的问题就是,在Activity中如何观察LiveData的数据变化呢?既然getUser()方法返回的就是一个LiveData对象,那么我们可不可以直接在Activity中使用如下写法呢:

 viewModel.getUser(userId).observe(this) { user -> }

这么做是完全错误的。因为每次调用getUser()方法返回的都是一个新的LiveData实例,而上述写法会一直观察旧的LiveData实例,从而根本无法观察到数据的变化。这种情况下的LiveData是不可观察的。

这个时候,switchMap()方法就可以派上用场了,它的使用场景非常固定:如果ViewModel中的某个LiveData对象是调用另外的方法获取的,那么就可以借助switchMap()方法,将这个LiveData对象转换成另外一个可观察的LiveData对象。

修改ViewModel中的代码,如下所示:

private val userIdLiveData = MutableLiveData<String>()

val user: LiveData<User> = Transformations.switchMap(userIdLiveData) { userId ->
           Repository.getUser(userId)
}

fun getUser(userId: String) {
  userIdLiveData.value = userId
}

这里定义了一个新的userIdLiveData对象,用来观察userId的数据变化,然后调用了Transformations.switchMap()方法,用来对另一个可观察的LiveData对象进行转换。

switchMap()方法同样接收两个参数:第一个参数传入新增的userIdLiveDataswitchMap()方法会对它进行观察;第二个参数是一个转换函数,注意,必须在这个转换函数中返回一个LiveData对象,因为switchMap()方法的工作原理就是要将转换函数中返回 的LiveData对象转换成另一个可观察的LiveData对象。 那么,只需要在转换函数中调用RepositorygetUser()方法来得到LiveData对象,并将它返回就可以了。

为了能更清晰地理解switchMap()的用法,再来梳理一遍它的整体工作流程。首先, 当外部调用ViewModel.getUser()方法来获取用户数据时,并不会发起任何请求或者函数调用,只会将传入的userId值设置到userIdLiveData当中。一旦userIdLiveData的 数据发生变化,那么观察userIdLiveData.switchMap()方法就会执行,并且调用编写的转换函数。然后在转换函数中调用Repository.getUser()方法获取真正的用户数据。 同时,switchMap()方法会将Repository.getUser()方法返回的LiveData对象转换成一 个可观察的LiveData对象,对于Activity而言,只要去观察这个LiveData对象就可以了。

修改Activity中的代码,如下所示:

getUserBtn.setOnClickListener {
  val userId = (0..100000).random().toString()
  viewModel.getUser(userId)
}

viewModel.user.observe(this, Observer { user ->
       infoText.text = user.firstName
})

具体的用法就是这样了,在Get User按钮的点击事件中使用随机函数生成了一个userId,然后调用ViewModel.getUser()方法来获取用户数据,但是这个方法现在不会有任何返回值了。等数据获取完成之后,可观察LiveData对象的observe()方法将会得到通知,在这里将获取的用户名显示到界面上。

在刚才的例子当中,调用ViewModel.getUser()方法时传入了一个userId参数,为了能够观察这个参数的数据变化,又构建了一个userIdLiveData,然后在switchMap()方法中再去观察这个LiveData对象就可以了。但是ViewModel中某个获取数据的方法有可能是没有参数的,这个时候代码应该怎么写呢?

其实这个问题并没有想象中复杂,写法基本上和原来是相同的,只是在没有可观察数据的情况 下,需要创建一个空的LiveData对象,示例写法如下:

private val refreshLiveData = MutableLiveData<Any?>()

val refreshResult = Transformations.switchMap(refreshLiveData) {
  Repository.refresh()
}

fun refresh() {
  refreshLiveData.value = refreshLiveData.value
}

这里定义了一个不带参数的refresh()方法,又对应地定义了一个refreshLiveData,但是它不需要指定具体包含的数据类型,因此这里将LiveData的泛 型指定成Any?即可。

refresh()方法中,只是将refreshLiveData原有的数据取出来(默认是空),再重新设置到refreshLiveData当中,这样就能触发一次数据变化。LiveData内部不会判断即将设置的数据和原有数据是否相同,只要调用了setValue()postValue()方法,就一定会触发数据变化事件。然后在Activity中观察refreshResult这个LiveData对象即可,这样只要调用了refresh()方法,观察者的回调函数中就能够得到最新的数据。

但是这和Lifecycle组件没什么关系,LiveData之所以能够成为ActivityViewModel之间通信的桥梁,并且还不会有内存泄漏的风险,靠的就是Lifecycles组件。LiveData在内部使用了Lifecycles组件来自我感知生命周期的变化,从而可以在Activity销毁的时候及时释放引用,避免产生内存泄漏的问题。

另外,由于要减少性能消耗,当Activity处于不可见状态的时候(比如手机息屏,或者被其他的Activity遮挡),如果LiveData中的数据发生了变化,是不会通知给观察者的。只有当Activity重新恢复可见状态时,才会将数据通知给观察者,而LiveData之所以能够实现这种细节的优 化,依靠的还是Lifecycle组件。

如果在Activity处于不可见状态的时候,LiveData发生了多次数据变化,当Activity恢复可见状态时,只有最新的那份数据才会通知给观察者,前面的数据在这种情况下相当于已经过期了,会被直接丢弃。

6 应用架构中的LiveData

LiveData 具有生命周期感知能力,遵循activityfragment等实体的生命周期。可以使用 LiveData 在这些生命周期所有者和生命周期不同的其他对象(例如 ViewModel 对象)之间传递数据。ViewModel 的主要责任是加载和管理与界面相关的数据,因此非常适合作为用于保留 LiveData 对象的备选方法。可以在 ViewModel 中创建 LiveData 对象,然后使用这些对象向界面层公开状态。此外,activityfragment不应保留 LiveData 实例,因为它们的用途是显示数据,而不是保持状态。

有时候可能会在数据层类中使用 LiveData 对象,但 LiveData 并不适合用于处理异步数据流。虽然可以使用 LiveData 转换和MediatorLiveData来实现此目的,但此方法的缺点在于:用于组合数据流的功能非常有限,并且所有 LiveData 对象(包括通过转换创建的对象)都会在主线程中观察到。下方是一段示例代码,展示了在 Repository中保留 LiveData 如何阻塞主线程:

class UserRepository {

    // DON'T DO THIS! LiveData objects should not live in the repository.
    fun getUsers(): LiveData<List<User>> {
        ...
    }

    fun getNewPremiumUsers(): LiveData<List<User>> {
        return TransformationsLiveData.map(getUsers()) { users ->
            // This is an expensive call being made on the main thread and may
            // cause noticeable jank in the UI!
            users
                .filter { user ->
                  user.isPremium
                }
          .filter { user ->
              val lastSyncedTime = dao.getLastSyncedTime()
              user.timeCreated > lastSyncedTime
                }
    }
}
学新通

7 扩展LiveData

如果观察者的生命周期处于STARTEDRESUMED状态,则LiveData会认为该观察者处于活跃状态。以下示例代码说明了如何扩展LiveData类:

class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
    private val stockManager = StockManager(symbol)

    private val listener = { price: BigDecimal ->
        value = price
    }

    override fun onActive() {
        stockManager.requestPriceUpdates(listener)
    }

    override fun onInactive() {
        stockManager.removeUpdates(listener)
    }
}

上述例子中的价格监听器实现包括以下重要方法:

  • LiveData 对象具有活跃观察者时,会调用onActive()方法。这意味着,需要从此方法开始观察股价更新;
  • LiveData 对象没有任何活跃观察者时,会调用onInactive()方法。由于没有观察者在监听,因此没有理由与 StockManager 服务保持连接;
  • setValue(T)方法将更新 LiveData 实例的值,并将更改告知活跃观察者;

可以使用 StockLiveData 类,如下所示:

public class MyFragment : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val myPriceListener: LiveData<BigDecimal> = ...
        myPriceListener.observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->
            // Update the UI.
        })
    }
}

observe()方法将与Fragment视图关联的LifecycleOwner作为第一个参数传递。这样做表示此观察者已绑定到与所有者关联的Lifecycle对象,这意味着:

  • 如果 Lifecycle 对象未处于活跃状态,那么即使值发生更改,也不会调用观察者;
  • 销毁 Lifecycle 对象后,会自动移除观察者;

LiveData 对象具有生命周期感知能力,这一事实意味着可以在多个ActivityFragmentService之间共享这些对象。为使示例保持简单,可以将 LiveData 类实现为一个单例,如下所示:

class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
    private val stockManager: StockManager = StockManager(symbol)

    private val listener = { price: BigDecimal ->
        value = price
    }

    override fun onActive() {
        stockManager.requestPriceUpdates(listener)
    }

    override fun onInactive() {
        stockManager.removeUpdates(listener)
    }

    companion object {
        private lateinit var sInstance: StockLiveData

        @MainThread
        fun get(symbol: String): StockLiveData {
            sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)
            return sInstance
        }
    }
}
学新通

并且可以在Fragment中使用它,如下所示:

class MyFragment : Fragment() {

  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    StockLiveData.get(symbol).observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->
              // Update the UI.
    })
  }
}

多个FragmentActivity可以观察 MyPriceListener 实例。仅当一个或多项系统服务可见且处于活跃状态时,LiveData 会连接到该服务。

8 合并多个LiveData

MediatorLiveDataLiveData的子类,允许合并多个LiveData源。只要任何原始的LiveData源对象发生更改,就会触发 MediatorLiveData 对象的观察者。

例如,如果界面中有可以从本地数据库或网络更新的 LiveData 对象,则可以向 MediatorLiveData 对象添加以下源:

  • 与存储在数据库中的数据关联的 LiveData 对象。
  • 与从网络访问的数据关联的 LiveData 对象。

Activity只需观察 MediatorLiveData 对象即可从这两个源接收更新。

参考

https://developer.android.谷歌.cn/topic/libraries/architecture/livedata#work_livedata
【源码解读】最详细的LiveData分析,从未如此丝滑
Jetpack 全家桶之 LiveData 使用及源码篇
jetpack - LiveData使用与源码解析
LiveData 源码分析
最新LiveData LifeCycle源码分析

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgfkchb
系列文章
更多 icon
同类精品
更多 icon
继续加载