android生命掌控组件LifeCycle

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还会执行吗?
不知道不要紧,继续往下看


背后原理

带着问题阅读无疑是最好的阅读,边阅读边思考,这里提出几个问题:

  1. 观测目标如何实时将自己的状态同步给订阅者 ?
  2. 众多的订阅者是如何管理、以及如何同步状态的 ?
  3. 观测目标执行完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);
}

以上代码,主要完成以下工作:

  1. 将订阅者LifeCycleObserver封装为ObserverWithState类,包含一个状态变量和统一的事件分发方法
  2. 将ObserverWithState添加到自己的mObserverMap中去,mObserverMap为FastSafeIterableMap类型,是一个HashMap+双链表结构
  3. 检查观测目标与这个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方法的意思就是:

  1. 首先对比订阅者集合中首尾节点状态是否一致,并且和观测目标当前是否一致,不一致说明需要进行状态同步
  2. 先判断最早的订阅者节点是否小于观测目标状态,小于就从订阅者集合倒序遍历进行状态同步,只有小于观测目标状态才会同步backwardPass
  3. 然后判断最后的节点状态是否大于观测目标状态,大于就正序遍历forwardPass所有订阅者节点,大于就进行事件分发
  4. 走完一遍后,在执行步骤1,如果状态还不一致,在执行2和3,因为有的订阅者可能和观测目标之间相隔1个以上的状态,所以需要再次执行while循环
  5. 最后的效果是,所有订阅者状态一步一步向观测目标的状态靠拢,而不是一个订阅者连续执行两个状态事件

Activity的生命周期事件如何传递进入LifecycleRegistry

简单来说,只需要在Activity的各个生命周期调用getLifecycle.handleLifecycleEvent()即把生命状态传递进去了,遗憾的是我在ComponentActivity类里面并没有看到生命周期去调用handleLifecycleEvent方法,很奇怪。找遍他的子类也没有,但是订阅者却能响应各个生命周期方法,肯定是哪里调用了的,只是我没有找到,如果读者的你找到,还望分享一下!


总结

Lifecycle是Jetpack的核心组件之一,使用很方便,能让你的订阅者时刻感知目标的状态;重点要理解Lifecycle如何管理众多的订阅者,生命状态如何在订阅者之间同步,以及状态迁移;看代码的你可能发现了这个问题,LifecycleRegistry添加订阅者后,并没有在OnDestroy后把这些订阅者remove掉,会不会导致内存泄漏,答案是否定的,因为LifecycleRegistry构造方法传递进去的是弱引用,不影响GC对Activity的垃圾回收

猜你喜欢

转载自blog.csdn.net/jackzhouyu/article/details/106048142