android JetPack组件之LifeCycle
简介
Lifecycle组件是JetPack的核心组件之一,JetPack的其他许多组件都会用到Lifecycle这一组件,如ViewModel、LiveData等。LifeCycle是负责观测Activity生命周期变化状态,并同步给它的订阅者,使订阅者实时感知如Activity生命状态,在正确的状态做正确的事,如Activity的onDestroy时,切断订阅者与观测目标的引用链,防止内存泄漏等问题
使用方法
我们只需要实现上图订阅者接口类,然后在Activity中调用getLifecycle()把订阅类add进去即可。基础类LifecycleObserver是一个空接口,如果实现该接口,我们可以任意写一些方法,在方法头部写上注解@OnLifecycleEvent(Lifecycle.Event.ON_xxx)即可,xxx写生命周期的各个方法,如DESTROY等,当观测目标生命周期执行onDestroy时就会执行该方法;如下伪代码:
1. 实现订阅者
class Subcriber implements LifecycleObser{
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void testOnCreate(){
Log.i("i am running create");
}
}
2. 将订阅者添加到观测类里面去
class MyActivity extends AppCompatActivity{
public void onCreate(savedInstanceState Bundle){
/**
getLifecycle为Activity已实现的方法
*/
getLifecycle().addObserver(new Subcriber());
}
}
订阅者还有其他的三个接口如LifecycleEventObserver等,这三个接口已经声明了方法了,我们实现这几个接口时,只需要在方法内部,判断方法参数Event事件,然后执行相应的逻辑即可,无须在写注解事件了;
这里提出一个问题,如果在Activity中,生命周期已经从onCreate走到了onResume,这时我们在onResume方法里面才添加一个Subcriber,那么上面的testOnCreate还会执行吗?
不知道不要紧,继续往下看
背后原理
带着问题阅读无疑是最好的阅读,边阅读边思考,这里提出几个问题:
- 观测目标如何实时将自己的状态同步给订阅者 ?
- 众多的订阅者是如何管理、以及如何同步状态的 ?
- 观测目标执行完onDestroy如何处理这些订阅者 ?
ComponentActivity
文章顶部的图片,先看看观测目标的ComponentActivity类,从它入手
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner{
private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
@NonNull
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
}
从上代码可以看出,对于ComponentActivity的生命周期监听的类是一个LifecycleRegistry,他负责对生命周期的监听。
LifecycleRegistry
了解添加订阅者之前,先介绍几个标志量:
private State mState; 当前观测目标状态、
private int mAddingObserverCounter = 0; 大于0,说明添加订阅者正在发生
private boolean mHandlingEvent = false; 观测目标状态变化了,正在同步给所有的订阅者
private boolean mNewEventOccurred = false; 以上两个至少有一个在发生
private ArrayList mParentStates = new ArrayList<>(); 临时状态栈,用于添加订阅者时记录
然后继续看看这个如何添加订阅者的:
public void addObserver(@NonNull LifecycleObserver observer) {
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
对订阅者再次封装包裹,主要是给他添加一个状态State,用于后续状态同步及事件分发
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
将订阅者添加到自己的mObserverMap管理组织起来,后续有事件时从mObserverMap取出来分发事件
mObserverMap是一个HashMap + 双链表的结构,value用双链表组织结构,start和end首尾节点
ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
如果之前已经添加过,就不做后续的工作直接返回,
if (previous != null) {
return;
}
mLifecycleOwner为当前LifecycleRegistry构造方法传入的观测目标的弱引用,
如果弱引用都没了,就说明观测目标都不存在了
LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
if (lifecycleOwner == null) {
// it is null we should be destroyed. Fallback quickly
return;
}
mAddingObserverCounter > 0表示正在为传入的observer做同步操作,可能添加进来时,观测目标
的声明周期走了好几个了,要给他补上
mHandlingEvent为true表明声明周期事件触发了,正在给他下面的订阅者进行事件分发
boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
获取observer的前一个节点,与当前观测目标对比,取小值
State targetState = calculateTargetState(observer);
mAddingObserverCounter++;
mAddingObserverCounter > 0表示正在给当前observer补上他的生命周期
状态对比statefulObserver.mState.compareTo(targetState) < 0,这个说明当前observer状态
比现在状态还小,他需要走upEvent事件
while ((statefulObserver.mState.compareTo(targetState) < 0
&& mObserverMap.contains(observer))) {
对当前状态压栈
pushParentState(statefulObserver.mState);
给这个observer分发事件,upEvent是从获取他的up事件,也就是从状态切换到事件
statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
popParentState();
//再次选最小值,知道while不满足,也就是和当前状态相等
targetState = calculateTargetState(observer);
}
if (!isReentrance) {
// we do sync only on the top level.
sync();
}
mAddingObserverCounter--;
}
//订阅者封装包裹类
static class ObserverWithState {
State mState;
LifecycleEventObserver mLifecycleObserver;
ObserverWithState(LifecycleObserver observer, State initialState) {
lifecycleEventObserver将其转换为LifecycleEventObserver类型
mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
mState = initialState;
}
void dispatchEvent(LifecycleOwner owner, Event event) {
State newState = getStateAfter(event);
mState = min(mState, newState);
这里事件分发
mLifecycleObserver.onStateChanged(owner, event);
mState = newState;
}
}
计算它前一个Observer和当前观测目标的声明周期状态,取最小值
private State calculateTargetState(LifecycleObserver observer) {
ceil取他前面的一个observer节点
Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);
State siblingState = previous != null ? previous.getValue().mState : null;
mParentStates是临时压栈的状态,也是在observer前面一个
State parentState = !mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() - 1)
: null;
返回最小
return min(min(mState, siblingState), parentState);
}
以上代码,主要完成以下工作:
- 将订阅者LifeCycleObserver封装为ObserverWithState类,包含一个状态变量和统一的事件分发方法
- 将ObserverWithState添加到自己的mObserverMap中去,mObserverMap为FastSafeIterableMap类型,是一个HashMap+双链表结构
- 检查观测目标与这个LifeCycleObserver状态,如果不同,要同步一下LifeCycleObserver到现在的状态
对订阅者的数据结构管理
在LifecycleRegistry中,mObserverMap是管理订阅者FastSafeIterableMap<LifecycleObserver, ObserverWithState>的类,这个类的结构是HashMap+双链表,mObserverMap是FastSafeIterableMap类型,看看他的结构体如何:
public class FastSafeIterableMap<K, V> extends SafeIterableMap<K, V> {
private HashMap<K, Entry<K, V>> mHashMap = new HashMap<>();
public V putIfAbsent(@NonNull K key, @NonNull V v) {
调用父类的get检查是否已经添加过
Entry<K, V> current = get(key);
if (current != null) {
return current.mValue;
}
在加入到HashMap中去
mHashMap.put(key, put(key, v));
return null;
}
}
public class SafeIterableMap<K, V> implements Iterable<Map.Entry<K, V>> {
Entry<K, V> mStart;
private Entry<K, V> mEnd;
遍历查找是否有k的value
protected Entry<K, V> get(K k) {
Entry<K, V> currentNode = mStart;
while (currentNode != null) {
if (currentNode.mKey.equals(k)) {
break;
}
currentNode = currentNode.mNext;
}
return currentNode;
}
新来的数据添加到mEnd之后,所以start是最新添加的,end是最后添加
protected Entry<K, V> put(@NonNull K key, @NonNull V v) {
Entry<K, V> newEntry = new Entry<>(key, v);
mSize++;
if (mEnd == null) {
mStart = newEntry;
mEnd = mStart;
return newEntry;
}
mEnd.mNext = newEntry;
newEntry.mPrevious = mEnd;
mEnd = newEntry;
return newEntry;
}
原始的存储element,多了上下两个指向变量
static class Entry<K, V> implements Map.Entry<K, V> {
@NonNull
final K mKey;
@NonNull
final V mValue;
Entry<K, V> mNext;
Entry<K, V> mPrevious;
}
}
小结:
很多细节写到了代码注释里面去了,但是这里为什么要使用HashMap+双链表呢?只用其中一个不行吗?答案肯定是可以的,但是为了效率问题,在同步订阅者状态时,需要不停的检测是否contains(observer),用hashMap效率快点,而队列则要全部遍历
生命状态同步
Lifecycle将生命周期划分为 状态 和 事件 来处理,如下枚举:
public enum Event {
ON_CREATE,
ON_START,
ON_RESUME,
ON_PAUSE,
ON_STOP,
ON_DESTROY,
ON_ANY //能匹配任何状态
}
public enum State {
DESTROYED,
INITIALIZED,
CREATED,
RESUMED;
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
}
而且每个状态执行了不同的方法会变成另一个状态,状态与事件的切换图如下:
在LifecycleRegistry中,将状态同步到订阅者时,就是根据上面图来对比执行的;假如某个订阅者A的状态是INITIALIZED,而观测目标B现在是CREATED状态,说明A比B的状态小,说明是上面的事件,对应代码就是upEvent方法,返回ON_CREATE事件,这个时候就把ON_CREATE事件同步给A,如下代码:
private void sync() {
LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
if (lifecycleOwner == null) {
throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"
+ "garbage collected. It is too late to change lifecycle state.");
}
while (!isSynced()) {
mNewEventOccurred = false;
如果最早的订阅者比观测目标大,说明是downEvent事件,就倒序遍历backwardPass
if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
backwardPass(lifecycleOwner);
}
同上
Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
if (!mNewEventOccurred && newest != null
&& mState.compareTo(newest.getValue().mState) > 0) {
forwardPass(lifecycleOwner);
}
}
mNewEventOccurred = false;
}
private void backwardPass(LifecycleOwner lifecycleOwner) {
递减iterator
Iterator<Entry<LifecycleObserver, ObserverWithState>> descendingIterator =
mObserverMap.descendingIterator();
开始遍历,而且没有新事件状态下来
while (descendingIterator.hasNext() && !mNewEventOccurred) {
Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next();
ObserverWithState observer = entry.getValue();
取出订阅者ObserverWithState
while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred
&& mObserverMap.contains(entry.getKey()))) {
获取状态的down事件,状态 --> 事件
Event event = downEvent(observer.mState);
pushParentState(getStateAfter(event));
将event分发到observer
observer.dispatchEvent(lifecycleOwner, event);
popParentState();
}
}
}
小结:
重点在于理解状态事件迁移图,就可以理解代码是如何将状态切换的,以及如何分发下去;sync方法的意思就是:
- 首先对比订阅者集合中首尾节点状态是否一致,并且和观测目标当前是否一致,不一致说明需要进行状态同步
- 先判断最早的订阅者节点是否小于观测目标状态,小于就从订阅者集合倒序遍历进行状态同步,只有小于观测目标状态才会同步backwardPass
- 然后判断最后的节点状态是否大于观测目标状态,大于就正序遍历forwardPass所有订阅者节点,大于就进行事件分发
- 走完一遍后,在执行步骤1,如果状态还不一致,在执行2和3,因为有的订阅者可能和观测目标之间相隔1个以上的状态,所以需要再次执行while循环
- 最后的效果是,所有订阅者状态一步一步向观测目标的状态靠拢,而不是一个订阅者连续执行两个状态事件
Activity的生命周期事件如何传递进入LifecycleRegistry
简单来说,只需要在Activity的各个生命周期调用getLifecycle.handleLifecycleEvent()即把生命状态传递进去了,遗憾的是我在ComponentActivity类里面并没有看到生命周期去调用handleLifecycleEvent方法,很奇怪。找遍他的子类也没有,但是订阅者却能响应各个生命周期方法,肯定是哪里调用了的,只是我没有找到,如果读者的你找到,还望分享一下!
总结
Lifecycle是Jetpack的核心组件之一,使用很方便,能让你的订阅者时刻感知目标的状态;重点要理解Lifecycle如何管理众多的订阅者,生命状态如何在订阅者之间同步,以及状态迁移;看代码的你可能发现了这个问题,LifecycleRegistry添加订阅者后,并没有在OnDestroy后把这些订阅者remove掉,会不会导致内存泄漏,答案是否定的,因为LifecycleRegistry构造方法传递进去的是弱引用,不影响GC对Activity的垃圾回收