LiveData 是 Google 推荐的基于观察者的数据持有者,可以认为是一个轻量级的RxJava。
一般来说不会单独使用,会和其他组件一起搭配,最常用的就是 ViewModel 了。
目录
1. 概述
1.1 什么是LiveData
官方定义:
LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData具有生命周期感知能
力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可
确保 LiveData仅更新处于活跃生命周期状态的应用组件观察者。
简单可以理解为一个 Observable
,同时能够感知生命周期。
如果搭配ViewModel,那么 ViewModel 就是 LiveData 的数据源,当数据更新后, LiveData 就会通知它的所有观察者。 与 RxJava 的方法不同的是, LiveData 并不是通知所有观察者,他只会通知处于 Active 状态的观察者,如果一个观察者处于 Paused 状态或 Destroyed 状态,那么它将不会受到通知。
1.2 为什么使用LiveData
- 解耦
- 避免内存泄漏
Activity、Service、Fragment可以安全的观察LiveData对象,而且不用在 onPaused 或者 onDestroy 方法中去解订阅。
一旦观察者恢复 resumed 状态, 它将会重新收到 LiveData 的最新数据。
2. 使用
这里省去导入流程,可以看 Jetpack学习之 Lifecycle
2.1 基本用法
LiveData 是一个抽象类, 它有一个比较简单又常用的实现类:MutableLiveData
, 这里举个栗子:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val mutableLiveData = MutableLiveData<String>()
// 1
mutableLiveData.observe(this, Observer {
Log.d(TAG, "onChanged: $it")
})
// 2
mutableLiveData.postValue("Hi Noel~")
}
}
注释1:observe()
有两个参数,分别是 LifecycleOwner
和 Observer<T>
也就是被观察者。
Kotlin代码的lambda表达式省略掉了其实现方法体,也就是 onChanged(@Nullable final String s)
方法,他能够在数据变化时,回调这个方法
注释2:postValue()
会在主线程更新数据,这样就会得到打印的结果,如下所示:
这里需要注意的是:
- 将更新界面的LiveData对象存储在ViewModel中,而不是将其存储在Activity或Fragment中:
(1)避免Activity或Fragment过于庞大,分离 ui 和数据
(2)将LiveData实例与特定Activity实例分离开,使LiveData对象在配置更改后继续存在 - 在onCreate方法中开始观察LiveData对象
不要在onResume方法中进行调用observe()
,因为会出现多次调用的问题。
确保Activity或Fragment变为活跃状态后具有可以立即显示的数据,因为应用组件处于STARTED 状态,就会从它正在观察的LiveData
对象接收最新值 - 当组件处于DESTROY状态时会自动取消订阅
- 除了使用
postValue()
,还可以使用setValue()
,区别是后者必须在主线程调用。如果需要在子线程中更新 LiveData, 可以使用 postValue 方法。
2.2 更改 LiveData 中的数据
2.2.1 Transformations.map 方法
和 RxJava 一样,我们可以对数据分发到指定对象之前,给它map一下,转化成另一种数据,比如下面代码,LiveData 原数据是 Int 型, 通过 map 转化成 String 类型(或则任何数据):
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val mutableLiveData = MutableLiveData<Int>()
mutableLiveData.observe(this, Observer {
Log.d(TAG, "onChanged1: $it")
})
val transformationsLiveData = Transformations.map(
mutableLiveData
) { input ->
("$input go")
}
transformationsLiveData.observe(this, Observer {
Log.d(TAG, "obChanged2: $it")
})
mutableLiveData.postValue(1)
}
2.2.2 Transformations.switchMap 方法
和 map 不同, switchMap返回的结果必须是一个 LiveData
数据,而且它可以通过一个 Boolean 值来选择监听对象
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mutableLiveData1 = MutableLiveData()
mutableLiveData2 = MutableLiveData()
// 1
liveDataSwitch = MutableLiveData()
// 如果是true,选择监听1,否则监听2
val transformedLiveData = Transformations.switchMap(liveDataSwitch) {
if (it) mutableLiveData1 else mutableLiveData2
}
transformedLiveData.observe(this, Observer {
Log.d(TAG, "onChanged: $it")
})
liveDataSwitch.postValue(false)
mutableLiveData1.postValue("noel")
mutableLiveData2.postValue("bye")
}
注释1:创建一个 MutableLiveData<Boolean>
来控制切换并复制给 liveDataSwitch
当 liveDataSwitch 的值为 true 时, 返回 mutableLiveData1, 否则返回 mutableLiveData2
这样最终输出的结果为2
2.2.3 MediatorLiveData合并数据源
MediatorLiveData
继承自 MutableLiveData, 它的作用是可以收集多个 LiveData。 如果其中一个 LiveData 数据源发生变化,那么也会通知到 MediatorLiveData
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val mutableLiveData1 = MutableLiveData<String>()
val mutableLiveData2 = MutableLiveData<String>()
// 创建一个用于合并数据源的LiveData
val liveDataManager = MediatorLiveData<String>()
// 添加数据 LiveData1, 并监听其变化
liveDataManager.addSource(mutableLiveData1) {
Log.d(TAG, "onChanged 1: $it")
}
// 添加数据 LiveData2, 并监听其变化
liveDataManager.addSource(mutableLiveData2) {
Log.d(TAG, "onChanged 2: $it")
}
liveDataManager.observe(this, Observer {
Log.d(TAG, "onChanged Data: $it")
})
mutableLiveData1.postValue("i always like u")
liveDataManager.postValue("thank u")
}
打印结果:
2.2.4 自定义LiveData
我们可以自定义一个 LiveData, 因为会有观察者来观察这个 LiveData, 所以观察者处于 STARTED 或者 RESUMED 时,LiveData 将会处于 Activity状态,这个时候通过实现 onActive()
/ onInactive()
来通知观察者。
下面是个例子,我们设定一个可以变化的数据类:
class ExtStringLiveData private constructor() : LiveData<String>() {
companion object {
private const val TAG = "ExtStringLiveData"
private var sInstance: ExtStringLiveData? = null
@MainThread
fun get(): ExtStringLiveData? {
if (sInstance == null) {
sInstance = ExtStringLiveData()
}
return sInstance
}
}
// 观察者处于活跃状态, 则通知它
override fun onActive() {
Log.d(TAG, "onActive")
// 这里的数据是写死的, 在实际项目中, 可以以监听器不断输出数据
value = "if u find me again, i will with u again"
}
override fun onInactive() {
Log.d(TAG, "onInactive")
// 这里的数据是写死的, 在实际项目中, 可以以监听器不断输出数据
// 在这之后, 就不会再想观察者发送数据直到观察者恢复active状态, 所以这一里在更改数据就不会通知了
value = "because I'm starting to regret it"
}
}
然后在 MainActivity 去监听它:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
ExtStringLiveData.get()?.observe(this, Observer {
Log.d(TAG, it)
})
}
打印结果为:
而在 LiveData 的 onInactive()
中更改的string数据, MainActivity 就打印不出来了。
3. 原理
3.1 LiveData 如何观察生命周期变化
因为组件都是通过调用 LiveData.observe(LifecycleOwner, Observer<? super T>)
进行监听,所以了解 Livecycle
的同学肯定就知道了其中的奥秘。我们来看看它的源码吧:
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
// 1
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return;
}
// 2
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// 3
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;
}
// 4
owner.getLifecycle().addObserver(wrapper);
}
注释1:如果当前声明周期是 DESTORYED
, 则拒绝注册
注释2:新建一个 LifecycleBoundObserver
实例,并传入相应参数
注释3:mObservers 的类型是 SafeIterableMap<Observer<? super T>, ObserverWrapper>mObservers
,key是观察者,value是注释2中创建的对象。
在这个map中的putIfAbsent
和 put
是有区别的,如果传入的 key 存在,就返回value,而不替换,如果 key 不存在,则添加进去,并返回null。
注释4:如果注释3的map中没有数据, 则调用 Lifecycle.addObserver
,传入的是 LivecycleBoundObserver
。 看来这个类比较重要,我们有必要去了解它的构造和作用。
3.2 LiveData 的 observe 方法回调
来看看 LivecycleBoundObserver
,它是 LiveData 的内部类:
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull final LifecycleOwner mOwner;
...
@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;
// 1
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
该类继承了 ObserverWrapper
类,重写了 shouldBeActive()
方法, 它的作用是用来判断当前传入的组件是否是 Active的, Active状态包括 STARTED 、 RESUMED
该类还实现了 LifecycleEventObserver
接口,当组件状态发生变化的时候, 会调用 onStateChanged()
,当组件处于 DESTORYED 状态是,会调用 removeObserver()
来移除 observer。
这也就是为什么,LiveData 不会给那些 Inactive 的组件发通知。
注释1: 调用父类的 activeStateChanged()
,我们来看看父类:
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) {
// 1
dispatchingValue(this);
}
}
}
ObserverWrapper
是一个抽象类,它包装了一个 Observer, activeStateChanged
会看 传进来的状态是否和此前状态是否相同,不同则,则执行 changeActiveCounter()
,来更新一下当前LiveData 观察者的活跃与非活跃的数量, 来决定调用 onActive()
或 onInactive()
其次,如果当前是 Active 状态,则调用注释1的 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;
}
如果当前处于可分发状态, 则会调用 considerNotify()
方法:
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
// 1
observer.mObserver.onChanged((T) mData);
}
即使是到了这里,也会一直在判断当前组件的状态,非常严格呢。
如果所有更新条件都满足,则会调用 Observer 的 onChanged()
, 也就从这里回调出去了~
3.3 postValue 方法
我们来看看调用 postValue()
/ setValue()
之后,LiveData 做了什么事情, 这里以 postValue 为例,来看看代码~
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
// 1
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;
}
// 2
setValue((T) newValue);
}
};
// 3
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
// 4
dispatchingValue(null);
}
注释1、2:做一个线程切换,切换到主线程中,并用线程安全的 synchronized()
注释3:确定当前线程是主线程,在非主线程中直接调用该方法会crash
注释4: 调用 dispatchingValue
,之后就是 considerNotify()
来通知观察者啦~
3.4 总结
LiveData
基于观察者模式实现和LifecyclerOwner
绑定后能感知生命周期- 只有处于活跃状态的 Owne r才会接收到数据变化的通知,Owner从非活跃状态变为活跃状态,会接收到新的数据通知
- Owner进入DESTROY状态会自动 remove Observer,不会担心内存泄露问题,如果希望一直接收到通知,可以使用
observeForever()
方法 - 主线程使用
setValue()
、工作线程使用postValue()
进行数据更新
参考文章
《Android进阶指北》Android Jetpack架构组件
LiveData官方文档