首先,LiveData是什么
LiveData是一种可以被观察的数据存储器类,它可以感知其他组件(比如Activity,Fragment)的生命周期,并只更新处于活跃状态的组件。当我们的应用组件处于STARTED或RESUMED状态,LiveData则会认为该组件处于活跃状态。
开始使用LiveData,LiveData一般搭配ViewModel一起使用
首先我们会创建一个ViewModel,在ViewModel里面在创建LiveData,并提供getter方法进行访问。
class NameViewModel : ViewModel() {
//LiveData是一个抽象类,一般使用它的 MutableLiveData 实现
val currentName: MutableLiveData by lazy {
MutableLiveData()
}
}
接着在Activity的onCreate()方法中获取我们的NumViewModel (在依赖了Android KTX 中的 Fragment KTX模块后,可以直接使用viewModels和activityViewModels属性委托绑定到ViewModel),接着为LiveData注册观察者。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//获取ViewModel对象
val model = ViewModelProvider(this,
ViewModelProvider.NewInstanceFactory()).get(NameViewModel::class.java)
//创建观察者对象
val nameObserver = Observer { name ->
//更新UI
}
//通过observe()来注册观察者
model.currentName.observe(this, nameObserver)
}
在注册观察者之后系统会立即调用onChange()方法,来提供currentName中的最新值,如果LiveData对象尚未在currentName中设置值,则onChange()方法不会被调用。
现在已经创建了LiveData对象并且设置了观察者。我们只需要更新LiveData对象就可以完成对onChange()方法的调用。LiveData提了setValue(T)和postValue(T)两个方法来更新值,第一个用来在主线程上使用,第二个用来在工作线程上使用。
button.setOnClickListener {
model.currentName.setValue("乌鸡哥")
}
LiveData 是怎么工作的
首先我们看下LiveData是如何注册一个观察者的
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer super T> observer) {
//该方法一定要在主线程上调用
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
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);
}
observe()方法的第一个参数是一个接口,提供了一个获取Lifecycle的方法,该对象可以对我们应用组件(如Activity,Fragment)的生命周期进行监听。LiveData能感知组件生命周期的能力就它带来的。第二个参数就是我们的观察者对象。
从上面的代码可以看出。如果该观察者所在的组件已经销毁,则什么也不会做。
紧接着,把我们传入的owner 和 observer 做了一个包装。这个包装类实现了GenericLifecycleObserver这个接口。
然后把我们的观察者作为key,包装类作为vlaue,存储到mObservers这个SafeIterableMap里。在这里做了一个判断,即一个观察者只能观察一个LiveData对象。
最后把我们的包装类和Lifecycle做了关联,这时我们的LiveData就获得了应用组件的生命周期感知能力。
那这个包装类是什么
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer super T> observer) {
super(observer);
mOwner = owner;
}
//判断该组件是否是活跃状态,大于等于STARTED时返回true
@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);
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
当观察者所在的组件生命周期发生改变后,会回调onStartChange,在里面会首先检查组件是不是已经销毁,销毁的话需要将该观察者对应的包装类从mObservers这个SafeIterableMap移除,最后还要移除包装类和Lifecycle的关联。
@MainThread
public void removeObserver(@NonNull final Observer super T> observer) {
assertMainThread("removeObserver");
ObserverWrapper removed = mObservers.remove(observer);
if (removed == null) {
return;
}
removed.detachObserver();
removed.activeStateChanged(false);
}
在里面首先会从mObservers这个SafeIterableMap里面移除该观察者对应的包装类。接着调用detachObserver()移除包装类和Lifecycle的关联。最后调用activeStateChanged(false)
如果组件没有销毁,则会直接调用activeStateChanged(shouldBeActive())
void activeStateChanged(boolean newActive) {
//如果状态没改变,什么也不做
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
//更新状态
mActive = newActive;
//当前LiveData没有任何活跃的观察者时为true
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);
}
}
在里面就是判断了一下LiveData里面是否还有活跃的观察者,从上面的代码看到,只有LiveData里面的活跃观察者从0变成1的时候才会调用onActive,并且只有活跃的观察者变成0的时候才会调用onInactive。最后判断了一个这个观察者是否是活跃的,如果是活跃的会调用dispatchingValue来向这一个观察者发送事件。
使用setValue来通知观察者更新数据
@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 {
//通知所有的观察者
for (Iterator, 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;
}
...
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
在观察者调用onChanged方法之前,仍会有很多的判断。比如检查观察者是不是活跃的。是不是已经通知过了。我们的LiveData里又一个mVersion,这个mVersion在每次的setValue操作后都会自增。而我们的ObserverWapper 也会有一个mLastVersion。比较这两个值就可以确定我们的观察者是否已经回调了onChanged。
LiveData还有一个observeForever方法。只需传递一个观察者对象就好。使用这个方法来注册观察者会是LiveData失去生命周期感知能力。我们需要自己在合适的生命周期回调方法中移除观察者
扩展LiveData
我们可以扩展一个LiveData来监听一些服务
class MoneyLiveData : LiveData(){
//金钱的管理类
private val manager = MoneyManager()
private val listener = { money: BigDecimal ->
value = money
}
override fun onActive() {
super.onActive()
manager.registerListener(listener)
}
override fun onInactive() {
super.onInactive()
manager.removeListener(listener)
}
}
这里包含一些重要的方法,onActive() 会在有活跃的观察者时调用,onInactive() 会在没有任何活跃的观察者时调用。setValue(T)会更新LiveData实例的值并将结果告知所有活跃的观察者,可以在Activity的onCreate()方法中使用
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val moneyLiveData: MoneyLiveData = ...
moneyLiveData.observe(this, Observer { money ->
//更新UI
})
}
转换LiveData
有时候我们会希望将LiveData对象通知观察者之前改变里面存储的值,这时我们可以使用map()方法。又或者转换成别的LiveData对象,这时我们可以使用switchMap()方法。
这时,我们应该使用转换过后的LiveData对象来注册观察者,而使用转换前的LiveData对象来更新数据。
val oldNameLiveData = MutableLiveData()
val newNameLiveData: LiveData = Transformations.map(oldNameLiveData) { oldName ->
"$oldName + 通过LiveData转换而来"
}
val userLiveData = MutableLiveData()
val nameAge: LiveData = Transformations.switchMap(userLiveData) {
user -> getNameAge(user)
}
fun getNameAge(user: User) :MutableLiveData {
return MutableLiveData().apply {
value = user.name + user.age
}
}