引子
LiveData 是能感知生命周期的,可观察的,粘性的,数据持有者。LiveData 用于以“数据驱动”方式更新界面。
换一种描述方式:LiveData 缓存了最新的数据并将其传递给正活跃的组件。
关于数据驱动的详解可以点击
这一篇就 LiveData 的面试题做一个归总、分析、解答。
1. LiveData 如何感知生命周期的变化?
先总结,再分析:
- Jetpack 引入了 Lifecycle,让任何组件都能方便地感知界面生命周期的变化。只需实现 LifecycleEventObserver 接口并注册给生命周期对象即可。
- LiveData 的数据观察者在内部被包装成另一个对象(实现了 LifecycleEventObserver 接口),它同时具备了数据观察能力和生命周期观察能力。
常规的观察者模式中,只要被观察者发生变化,就会无条件地通知所有观察者。比如java.util.Observable
:
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!hasChanged())
return;
arrLocal = obs.toArray();
clearChanged();
}
// 无条件地遍历所有观察者并通知
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
}
// 观察者
public interface Observer {
void update(Observable o, Object arg);
}
LiveData 在常规的观察者模式上附加了条件,若生命周期未达标,即使数据发生变化也不通知观察者。这是如何实现的?
生命周期
生命周期是一个对象从构建到消亡过程中的各个状态的统称。
比如 Activity 的生命周期用如下函数依次表达:
onCreate()
onStart()
onResume()
onPause()
onStop()
onDestroy()
要观察生命周期就不得不继承 Activity 重写这些方法,想把生命周期的变化分发给其他组件就很麻烦。
于是 Jetpack 引入了 Lifecycle,以让任何组件都可方便地感知生命周期的变化:
public abstract class Lifecycle {AtomicReference<>();
// 添加生命周期观察者
public abstract void addObserver(LifecycleObserver observer);
// 移除生命周期观察者
public abstract void removeObserver(LifecycleObserver observer);
// 获取当前生命周期状态
public abstract State getCurrentState();
// 生命周期事件
public enum Event {
ON_CREATE,
ON_START,
ON_RESUME,
ON_PAUSE,
ON_STOP,
ON_DESTROY,
ON_ANY;
}
// 生命周期状态
public enum State {
DESTROYED,
INITIALIZED,
CREATED,
STARTED,
RESUMED;
}
// 判断至少到达了某生命周期状态
public boolean isAtLeast(State state) {
return compareTo(state) >= 0;
}
}
Lifecycle 即是生命周期对应的类,提供了添加/移除生命周期观察者的方法,在其内部还定义了全部生命周期的状态及对应事件。
生命周期状态是有先后次序的,分别对应着由小到大的 int 值。
生命周期拥有者
描述生命周期的对象已经有了,如何获取这个对象需要个统一的接口(不然直接在 Activity 或者 Fragment 中新增一个方法吗?),这个接口叫LifecycleOwner
:
public interface LifecycleOwner {
Lifecycle getLifecycle();
}
Activity 和 Fragment 都实现了这个接口。
只要拿到 LifecycleOwner,就能拿到 Lifecycle,然后就能注册生命周期观察者。
生命周期 & 数据观察者
生命周期观察者是一个接口:
// 生命周期观察者(空接口,用于表征一个类型)
public interface LifecycleObserver {}
// 生命周期事件观察者
public interface LifecycleEventObserver extends LifecycleObserver {
void onStateChanged(LifecycleOwner source, Lifecycle.Event event);
}
要观察生命周期只要实现LifecycleEventObserver
接口,并注册给LifeCycle
即可。
除了生命周期观察者外,LiveData 场景中还有一个数据观察者:
// 数据观察者
public interface Observer<T> {
// 数据发生变化时回调
void onChanged(T t);
}
数据观察者 会和 生命周期拥有者 进行绑定:
public abstract class LiveData<T> {
// 数据观察者容器
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
new SafeIterableMap<>();
public void observe(
LifecycleOwner owner, // 被绑定的生命周期拥有者
Observer<? super T> observer // 数据观察者
) {
...
// 将数据观察者包装成 LifecycleBoundObserver
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// 存储观察者到 map 结构
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
...
// 注册生命周期观察者。
owner.getLifecycle().addObserver(wrapper);
}
}
在观察 LiveData 时,需传入两个参数,生命周期拥有者和数据观察者。这两个对象经过LifecycleBoundObserver
的包装被绑定在了一起:
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
// 持有生命周期拥有者
final LifecycleOwner mOwner;
LifecycleBoundObserver(LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
// 生命周期变化回调
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
...
activeStateChanged(shouldBeActive())
...
}
}
// 观察者包装类型
private abstract class ObserverWrapper {
// 持有原始数据观察者
final Observer<? super T> mObserver;
// 注入数据观察者
ObserverWrapper(Observer<? super T> observer) {mObserver = observer;}
// 尝试将最新值分发给当前数据观察者
void activeStateChanged(boolean newActive) {...}
...
}
LifecycleBoundObserver 实现了LifecycleEventObserver
接口,并且它被注册给了绑定的生命周期对象,遂具备了生命周期感知能力。同时它还持有了数据观察者,所以它还具备了数据观察能力。
2. LiveData 是如何避免内存泄漏的?
先总结,再分析:
- LiveData 的数据观察者通常是匿名内部类,它持有界面的引用,可能造成内存泄漏。
- LiveData 内部会将数据观察者进行封装,使其具备生命周期感知能力。当生命周期状态为 DESTROYED 时,自动移除观察者。
内存泄漏是因为长生命周期的对象持有了短生命周期对象,阻碍了其被回收。
观察 LiveData 数据的代码通常这样写:
class LiveDataActivity : AppCompatActivity() {
private val viewModel by lazy {
ViewModelProviders.of(this@LiveDataActivity).get(MyViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.livedata.observe(this@LiveDataActivity) {
// 观察 LiveData 数据更新(匿名内部类)
}
}
}
Observer 作为界面的匿名内部类,它会持有界面的引用,同时 Observer 被 LiveData 持有,LivData 被 ViewModel 持有,而 ViewModel 的生命周期比 Activity 长。(为啥比它长,可以点击这里)。
最终的持有链如下:NonConfigurationInstances 持有 ViewModelStore 持有 ViewModel 持有 LiveData 持有 Observer 持有 Activity。
所以得在界面生命周期结束的时候移除 Observer,这件事情,LiveData 帮我们做了。
在 LiveData 内部 Observer 会被包装成LifecycleBoundObserver
:
class LifecycleBoundObserver extends ObserverWrapper
implements LifecycleEventObserver {
final LifecycleOwner mOwner;
LifecycleBoundObserver(LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
// 获取当前生命周期
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
// 若生命周期为 DESTROYED 则移除数据观察者并返回
if (currentState == DESTROYED) {
removeObserver(mObserver);
return
}
...
}
...
}