定义
简单地说,LiveData是一个数据持有类。它具有以下特点:
为什么需要LiveData
从LiveData具有的特点,我们就能联想到它能够解决我们遇到的什么问题。LiveData具有以下优点:
-
能够保证数据和UI统一
这个和LiveData采用了观察者模式有关,LiveData是被观察者,当数据有变化时会通知观察者(UI)。 -
减少内存泄漏
这是因为LiveData能够感知到组件的生命周期,当组件处于DESTROYED状态时,观察者对象会被清除掉。 -
当Activity停止时不会引起崩溃
这是因为组件处于非激活状态时,不会收到LiveData中数据变化的通知。 -
不需要额外的手动处理来响应生命周期的变化
这一点同样是因为LiveData能够感知组件的生命周期,所以就完全不需要在代码中告诉LiveData组件的生命周期状态。 -
组件和数据相关的内容能实时更新
组件在前台的时候能够实时收到数据改变的通知,这是可以理解的。当组件从后台到前台来时,LiveData能够将最新的数据通知组件,这两点就保证了组件中和数据相关的内容能够实时更新。 -
针对configuration change时,不需要额外的处理来保存数据
我们知道,当你把数据存储在组件中时,当configuration change(比如语言、屏幕方向变化)时,组件会被recreate,然而系统并不能保证你的数据能够被恢复的。当我们采用LiveData保存数据时,因为数据和组件分离了。当组件被recreate,数据还是存在LiveData中,并不会被销毁。 -
资源共享
通过继承LiveData类,然后将该类定义成单例模式,在该类封装监听一些系统属性变化,然后通知LiveData的观察者,这个在继承LiveData中会看到具体的例子。
LiveData使用
在了解LiveData定义和优点后,那它到底怎么应用呢?LiveData有几种使用方式:
- 使用LiveData对象
- 继承LiveData类
使用LiveData对象
使用LiveData对象主要有以下几个步骤:
- 创建保存特定数据类型的LiveData实例;
- 创建Observer对象,作为参数传入LiveData.observe()方法添加观察者;
- 更新Livedata对象存储的数据
创建LiveData实例
Android文档中建议LiveData配合ViewModel使用更加哦,其实也可以不使用ViewModel,但是一定要做到LiveData中保存的数据和组件分离
var mCurrentName: MutableLiveData<String> = MutableLiveData()
创建Observer对象,添加观察者
在onCreate()方法中通过LiveData.observe()方法添加观察者,当数据变化时会通过回调方法通知观察者
mNameViewModel.mCurrentName.observe(this, Observer { name: String? ->
binding.nameText.text = name ?: ""
})
更新LiveData中的数据
在上面我们已经订阅了LiveData数据变化,我们在xml中增加按钮来改变LiveData中的数据。
binding.nameBtn.addClickAction {
mNameViewModel.mCurrentName?.value = "liveData"
}
我们发现按钮点击,LiveData数据变化时,上面的lambda表达式中会收到更新的通知。
继承LiveData类
除了直接使用LiveDatad对象外,我们还可以通过集成LiveData类来定义适合特定需求的LiveData。下面继承LiveData类的例子,验证下LiveData的其中一个优点——资源共享。
class TestLiveData() : LiveData<String>() {
var mContextWeakReference: WeakReference<Context>? = null
private constructor(context: Context) : this() {
this.mContextWeakReference = WeakReference(context)
}
companion object {
var shared: TestLiveData? = null
}
fun getInstance(context: Context): TestLiveData? {
if (shared == null) {
shared = TestLiveData(context)
}
return shared
}
/**
* 当这个方法被调用时,
* 表示LiveData的观察者数量从0变为了1,
* 这时就我们的位置监听来说,就应该注册我们的时间监听了。
*/
override fun onActive() {
super.onActive()
registerReceiver()
}
/**
* 这个方法被调用时,
* 表示LiveData的观察者数量变为了0,
* 既然没有了观察者,也就没有理由再做监听,此时我们就应该将位置监听移除。
*/
override fun onInactive() {
super.onInactive()
unregisterReceiver()
}
private fun registerReceiver() {
val intentFilter = IntentFilter()
intentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION)
mContextWeakReference?.get()?.registerReceiver(mReceiver, intentFilter)
}
private fun unregisterReceiver() {
mContextWeakReference?.get()?.unregisterReceiver(mReceiver)
}
private val mReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
if (WifiManager.RSSI_CHANGED_ACTION == action) {
val wifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200)
val wifiLevel = WifiManager.calculateSignalLevel(
wifiRssi, 4)
shared?.setValue("wifiRssi = " + wifiRssi + " wifiLevel = " + wifiLevel)
}
}
}
}
TestLiveData是个继承了LiveData的单例类,在onActive()和onInactive()方法中分别注册和反注册Wifi信号强度的广播。然后在广播接收器中更新TestLiveData对象。在使用的时候就可以通过TestLiveData.getInstance()方法,然后通过调用observe()方法来添加观察者对象,订阅Wifi信息强度变化。
- onActive(),此方法是当处于激活状态的observer个数从0到1时,该方法会被调用。
- onInactive() ,此方法是当处于激活状态的observer个数从1变为0时,该方法会被调用。
时序图
LiveData时序图LiveData主要涉及到的时序有三个:
- 在Fragment/Activity中通过LiveData.observer()添加观察者(observer()方法中的第二个参数)。
- 根据Fragment/Activity生命周期发生变化时,移除观察者或者通知观察者更新数据。
- 当调用LiveData的setValue()、postValue()方法后,通知观察者更新数据。
改变LiveData数据
LiveData提供了两种改变数据的方法:setValue()和postValue()。区别是setValue()要在主线程中调用,而postValue()既可在主线程也可在子线程中调用。我们先看setValue()方法的具体实现:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");//判断当前线程是否是主线程,不是主线程就抛出异常
mVersion++;
mData = value;
dispatchingValue(null);
}
再看下postValue()方法的具体实现:
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
// 会在主线程中执行 mPostValueRunnable中的内容。
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
// 在主线程中调用setValue()方法
setValue((T) newValue);
}
};
observe与observeForever
LiveData提供了两种添加观察者的方法:observeForever()、observe()。
查看源码:
observeForever
@MainThread
public void observeForever(@NonNull Observer<T> observer) {
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
wrapper.activeStateChanged(true);//设置为true,观察者会一直受到数据的变化
}
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
if (mActive) {
dispatchingValue(this);//notify数据
}
}
通过observeForever()添加观察者,观察者会一直受到数据的变化回到,而不是在组件处于STARTED和RESUMED状态下才会收到,因为这是LifecycleOwner对象就不再是组件了,而是ALWAYS_ON;另外通过该方法添加观察者后,要手动调用removeObserver()方法来停止观察者接收回调通知。
observe
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// mObservers可以理解成一个类似Map的容器,putIfAbsent()方法是判断容器中的observer(key)
// 是否有已经和wrapper(value)关联,如果已经关联则返回关联值,否则关联并返回wrapper。
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);//条件LifecycleOwner的生命周期观察者
}
将LifecycleOwner对象和Observer对象封装成LifecycleBoundObserver对象。
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@NonNull final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);//区别observeForever是在DESTROYED时已帮removeObserver,不需手动remove
return;
}
activeStateChanged(shouldBeActive());//在activity处于STARTED状态时通知监听者
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
LiveData的转换
有时候有这样的需求,需要在LiveData将变化的数据通知给观察者前,改变数据的类型;或者是返回一个不一样的LiveData。
这里介绍一个类Transformations,它可以帮助完成上面的这些操作。
- Transformations.map()
在LiveData数据的改变传递到观察者之前,在数据上应用一个方法:
var userLiveData: MutableLiveData<UserModel> = MutableLiveData()
/**
* 需要在LiveData将变化的数据通知给观察者前,改变数据的类型
* 直接赋值,source返回为null
*/
var userNameLiveData: LiveData<String> = Transformations.map<UserModel, String>(userLiveData, { user ->
user.userName
})
@MainThread
public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source,
@NonNull final Function<X, Y> func) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(source, new Observer<X>() {
@Override
public void onChanged(@Nullable X x) {
result.setValue(func.apply(x));//改变时才设置值
}
});
return result;
}
- Transformations.switchMap()
与Transformations.map()类似,只不过这里传递个switchMap()的方法必须返回一个LiveData对象。
@MainThread
public static <X, Y> LiveData<Y> switchMap(@NonNull LiveData<X> trigger,
@NonNull final Function<X, LiveData<Y>> func) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(trigger, new Observer<X>() {
LiveData<Y> mSource;
@Override
public void onChanged(@Nullable X x) {
LiveData<Y> newLiveData = func.apply(x);
if (mSource == newLiveData) {
return;
}
if (mSource != null) {
result.removeSource(mSource);
}
mSource = newLiveData;
if (mSource != null) {
result.addSource(mSource, new Observer<Y>() {
@Override
public void onChanged(@Nullable Y y) {
result.setValue(y);
}
});
}
}
});
return result;
}
示例
var userNameLiveData2: LiveData<String> = Transformations.switchMap<UserModel,String>(userLiveData, { user ->
var liveData: MutableLiveData<String> = MutableLiveData()
liveData.value = user.userName
liveData
})
参考:
网友评论