以下是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
,它能够在Activity
、Fragment
和Service
之中正确的处理生命周期。 乍看之下,LiveData
挺鸡肋的,事实也确实如此,因为LiveData
能够实现的功能RxJava
也可以实现,而且与LiveData
相比, RxJava
拥有着更加丰富的生态,当然,谷歌的官方架构仍然值得我们去学习。
LiveData
是一种可观察的数据存储器类,它可以包含任何类型的数据。与常规的可观察类不同,LiveData
具有生命周期感知能力,意思是它遵循其它应用组件(如 Activity
、Fragment
或Service
)的生命周期。这种感知能力可确保LiveData
仅更新处于活跃生命周期状态的(应用组件)观察者。
如果观察者的生命周期处于STARTED
或RESUMED
状态,则LiveData
会认为该观察者处于活跃状态。LiveData
只会将更新通知给活跃的观察者,而非活跃观察者不会收到更改通知。 因此,可以在实现LifecycleOwner
接口的类中注册观察者,当相应的Lifecycle
对象的状态变为DESTROYED
时,便可移除此观察者。 这对于Activity
和Fragment
特别有用,这样它们就可以放心地观察LiveData
对象,而不必担心内存泄露(当Activity
和 Fragment
的生命周期结束时,系统会立即退订它们)。
使用LiveData
具有以下优势:
UI
。 LiveData
遵循观察者模式,当数据发生变化时,LiveData
会通知Observer
对象,可以在这些 Observer
对象中更新界面,无需在每次应用数据发生变化时更新界面,因为观察者会完成更新;Lifecycle
对象,并在其关联的生命周期遭到销毁后进行自我清理;Activity
停止而导致崩溃。 如果观察者的生命周期处于非活跃状态(如返回栈中的Activity
),它不会接收任何 LiveData
事件;LiveData
将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化;Activity
会在返回前台后立即接收最新的数据;Activity
或Fragment
,它会立即接收最新的可用数据;LiveData
对象以封装系统服务,以便在应用中共享它们。LiveData
对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察 LiveData
对象;LiveData
经常与ViewModel
在一起使用,虽然它也可以单独用在别的地方,但是在绝大多数情况下,它是使用在ViewModel
当中的。
LiveData
和ViewModel
在整个MVVM
架构中担当数据驱动的职责,这也是MVVM
模式中ViewModel
层的作用。
为什么不把Activity
的实例传给ViewModel
呢,这样ViewModel
不就能主动对Activity
进行通知了吗?这是因为ViewModel
的生命周期是长于Activity
的,如果把Activity
的实例传给ViewModel
,就很有可能会因为Activity
无法释放而造成内存泄漏,这是一种非常错误的做法。
LiveData
的基本用法LiveData
的实例用来存储某种类型的数据,通常在ViewModel
类中完成;onChanged()
方法的Observer
对象,该方法可以控制 LiveData
对象存储的数据更改时会发生什么。通常情况下,可以在界面控制器(如Activity
或Fragment
)中创建 Observer
对象;observe()
方法将 Observer
对象附加到 LiveData
对象,observe()
方法会采用LifecycleOwner
对象,这样会使 Observer
对象订阅 LiveData
对象,以使其收到有关更改的通知。通常情况下,可以在界面控制器(如Activity
或Fragment
)中附加 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"
}
LiveData
对象LiveData
是一种可用于任何数据类型的封装容器,其中包括可实现 Collections
的对象,如List
。LiveData
对象通常存储在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
对象中,而不是将其存储在Activity
或Fragment
中,原因如下:避免 Activity
和Fragment
过于庞大。现在,这些界面控制器负责显示数据,但不负责存储数据状态。将 LiveData
实例与特定的Activity
或Fragment
实例分离开,并使 LiveData
对象在配置更改后继续存在。
LiveData
常用方法:
MutableLiveData
是一种可变的LiveData
,它的用法很简单,主要有3
种读写数据的方法,分别是getValue()
、setValue()
和postValue()
方法:
getValue()
方法用于获取LiveData
中包含的数据;setValue()
方法用于给LiveData
设置数据,但是只能在主线程中调用;postValue()
方法用于在非主线程中给LiveData
设置数据;以下是MutableLiveData
和LiveData
的源码:
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> {
}
LiveData
对象在大多数情况下,应用组件的 onCreate()
方法是开始观察LiveData
对象的正确着手点,原因如下:
Activity
或Fragment
的 onResume()
方法进行冗余调用;Activity
或Fragment
变为活跃状态后具有可以立即显示的数据。一旦应用组件处于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
}
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
对象。
LiveData
的源码分析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);
}
}
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
总是返回true
,activeStateChange(true)
方法的参数也是固定的true
,所以这个方法是不依赖生命周期状态的。在使用完observeForever
函数后,一定要主动移除Observer
,避免内存泄露和空指针异常。
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);
}
}
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
的时候把ObserverWrapper
的mLastVersion
设置成跟LiveData.version
一致即可。
LiveData
如果希望在LiveData
对象分派给观察者之前对存储在其中的值进行更改,或者需要根据另一个实例的值返回不同的 LiveData
实例,Lifecycle
软件包提供Transformations
类,提供了可应对这些情况的方法。
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
的观察者。
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()
方法,并且让它调用Repository
的getUser()
方法来获取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()
方法同样接收两个参数:第一个参数传入新增的userIdLiveData
,switchMap()
方法会对它进行观察;第二个参数是一个转换函数,注意,必须在这个转换函数中返回一个LiveData
对象,因为switchMap()
方法的工作原理就是要将转换函数中返回 的LiveData
对象转换成另一个可观察的LiveData
对象。 那么,只需要在转换函数中调用Repository
的getUser()
方法来得到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
之所以能够成为Activity
与ViewModel
之间通信的桥梁,并且还不会有内存泄漏的风险,靠的就是Lifecycles
组件。LiveData
在内部使用了Lifecycles
组件来自我感知生命周期的变化,从而可以在Activity
销毁的时候及时释放引用,避免产生内存泄漏的问题。
另外,由于要减少性能消耗,当Activity
处于不可见状态的时候(比如手机息屏,或者被其他的Activity
遮挡),如果LiveData
中的数据发生了变化,是不会通知给观察者的。只有当Activity
重新恢复可见状态时,才会将数据通知给观察者,而LiveData
之所以能够实现这种细节的优 化,依靠的还是Lifecycle
组件。
如果在Activity
处于不可见状态的时候,LiveData
发生了多次数据变化,当Activity
恢复可见状态时,只有最新的那份数据才会通知给观察者,前面的数据在这种情况下相当于已经过期了,会被直接丢弃。
LiveData
LiveData
具有生命周期感知能力,遵循activity
和fragment
等实体的生命周期。可以使用 LiveData
在这些生命周期所有者和生命周期不同的其他对象(例如 ViewModel
对象)之间传递数据。ViewModel
的主要责任是加载和管理与界面相关的数据,因此非常适合作为用于保留 LiveData
对象的备选方法。可以在 ViewModel
中创建 LiveData
对象,然后使用这些对象向界面层公开状态。此外,activity
和fragment
不应保留 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
}
}
}
LiveData
如果观察者的生命周期处于STARTED
或RESUMED
状态,则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
对象具有生命周期感知能力,这一事实意味着可以在多个Activity
、Fragment
和Service
之间共享这些对象。为使示例保持简单,可以将 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.
})
}
}
多个Fragment
和Activity
可以观察 MyPriceListener
实例。仅当一个或多项系统服务可见且处于活跃状态时,LiveData
会连接到该服务。
LiveData
源MediatorLiveData
是LiveData
的子类,允许合并多个LiveData
源。只要任何原始的LiveData
源对象发生更改,就会触发 MediatorLiveData
对象的观察者。
例如,如果界面中有可以从本地数据库或网络更新的 LiveData
对象,则可以向 MediatorLiveData
对象添加以下源:
LiveData
对象。LiveData
对象。Activity
只需观察 MediatorLiveData
对象即可从这两个源接收更新。
https://developer.android.google.cn/topic/libraries/architecture/livedata#work_livedata
【源码解读】最详细的LiveData分析,从未如此丝滑
Jetpack 全家桶之 LiveData 使用及源码篇
jetpack - LiveData使用与源码解析
LiveData 源码分析
最新LiveData LifeCycle源码分析