Android Jetpack之Lifecycle使用及源码分析

一、前言

关于Android Jetpack是什么不在赘述,不了解的同学可以看看Android架构木木的这篇文章Android Jetpack让Android一飞冲天

此文章为Android Jetpack系列文章,内容如下:
Android Jetpack之ViewModel使用及源码分析
Android Jetpack之Lifecycle使用及源码分析
未完待续。。。。。。

二、使用Lifecycle意义

通过Lifecycle 组件我们可以轻松的感知Activity或者Fragment的生命周期的变化。在MVP架构中,常规的感知生命周期变化的做法,需要在BaseActicity中实现一个具有生命周期方法的接口,这种做法导致代码的耦合性较强,Lifecycle 的实现则更加优雅。

三、使用方法

1、首先实现一个观察者

public class TestLifecycleObserver implements LifecycleObserver {

    private final static String TAG = "TestLifecycleObserver";

    //注解表示此处监听onCreate的生命周期
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void onCreate() {
        Log.v(TAG, "onCreate...");
    }

    //注解表示此处监听onResume的生命周期
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void onResume() {
        Log.v(TAG, "onResume...");
    }

    //注解表示此处监听onDestroy的生命周期
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public void onDestroy() {
        Log.v(TAG, "onDestroy...");
    }

}

2、在被观察者中进行注册

public class MainActivity extends Activity implements LifecycleOwner {

    private LifecycleRegistry registry;
    private TestLifecycleObserver testLifecycleObserver = new TestLifecycleObserver();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
        registry.setCurrentState(Lifecycle.State.CREATED);
    }

    @Override
    protected void onResume() {
        super.onResume();
        registry.setCurrentState(Lifecycle.State.RESUMED);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        registry.setCurrentState(Lifecycle.State.DESTROYED);
        registry.removeObserver(testLifecycleObserver);
    }

    private void init() {
        registry = new LifecycleRegistry(this);
        registry.addObserver(testLifecycleObserver);
    }

    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return registry;
    }
}

看到这里有同学可能觉得,这和传统的MVP方式没有太大区别,需要实现LifecycleOwner接口,并且在相应的生命周期方法里面触发对应的方法,所以同样会有耦合,需要自己去控制相应的逻辑。
事实上,在26.0.1版本后的support库中的Activity、Fragment已经为我们实现了LifecycleOwner接口,我们只需要调用addObserver添加观察者,并且在合适的时机解注册即可。之前的版本可以采取以上方式,自己实现LifecycleOwner接口,也可以实现生命周期变化的观察。

四、源码分析

同样我们带着问题来看代码,通过以上的使用方法,我们可能会有如下问题:
1、LifecycleRegistry内部是如何维护观察者的
2、setCurrentState的时候发生了什么
3、LifecycleRegistry初始化时传入了this参数会不会造成内存泄漏

1、LifecycleRegistry的基本结构

先看看LifecycleRegistry中关键的部分,代码如下:

public class LifecycleRegistry extends Lifecycle {
    /**
     * 一个列表,并且可以在遍历期间添加或者删除元素
     * 新观察者的状态一定是小于等于之前的观察者的
     */
    private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap =
            new FastSafeIterableMap<>();
    /**
     * 当前状态
     */
    private State mState;
    /**
     * 以弱引用保存LifecycleOwner,防止内存泄漏
     */
    private final WeakReference<LifecycleOwner> mLifecycleOwner;
}

//LifecycleRegistry继承自Lifecycle
public abstract class Lifecycle {

    @SuppressWarnings("WeakerAccess")
    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(@NonNull State state) {
            return compareTo(state) >= 0;
        }
    }

}

由于Lifecycle用enum的形式定义了所有State,并且各个状态是按照固定的顺序来变化的,所以State具备了大小和顺序的概念。LifecycleRegistry将事件通知给所有观察者之前,存在一个同步的过程。这个同步的过程中,前面的观察者已经通知到了,后面的观察者还没被通知,于是所有观察者之间的状态就不一致了,各观察者状态之间便产生了大小关系,只有第一个观察者的状态等于最后一个观察者的状态,并且等于LifecycleRegistry中的当前状态mState,才说明状态同步整个完成了。
各个状态的路径变化如下图:


20191129104813484.png

2、观察者的注册及保存

先来看看LifecycleRegistry的addObserver方法

    @Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        //第一步
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        //第二步
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

        if (previous != null) {
            return;
        }
        //这里持有的是LifecycleOwner的弱引用,通常是Activity
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            // it is null we should be destroyed. Fallback quickly
            return;
        }
        //第三步
        boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
        State targetState = calculateTargetState(observer);
        mAddingObserverCounter++;
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
            pushParentState(statefulObserver.mState);
            statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
            popParentState();
            // mState / subling may have been changed recalculate
            targetState = calculateTargetState(observer);
        }

        if (!isReentrance) {
            // we do sync only on the top level.
            sync();
        }
        mAddingObserverCounter--;
    }

大致可以分为三步:
第一步,重新包装观察者生成一个ObserverWithState。LifecycleObserver的关键的生命周期接口实现既可以像上面例子一样通过@OnLifecycleEvent(XXX)注解实现,也可以继承相应的接口实现。所以这个类的主要作用是统一接口回调,并且保存了观察者的状态。
第二步,将封装后的statefulObserver 保存进以原始参数observer为key的map中去,同时判断是否这个observer之前已经添加过了,如果previous 不为null,表示之前已经添加过了,就直接退出流程;如果lifecycleOwner 为null,说明lifecycleOwner已经死亡了,那么也可以直接退出。顺便提一句,LifecycleOwner是作为弱引用传递进来的。
第三步,将新的观察者加进列表之后,通过while循环将它的状态同步到最新的状态mState。upEvent的返回值是传入state的下一个事件,这说明新的观察者仍然会连续收到从INITIALIZED到当前状态之间的所有状态,这里可以理解为是粘性的。

ObserverWithState的代码如下:

static class ObserverWithState {
        State mState;
        LifecycleEventObserver mLifecycleObserver;

        ObserverWithState(LifecycleObserver observer, State initialState) {
            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;
        }
    }

可以看到在构造函数中调用来Lifecycling类的lifecycleEventObserver方法来封装观察者,这个方法就是我们前面提到的,将所有观察者的接口适配成一致的。

再来看看观察者的保存列表FastSafeIterableMap,其关键代码如下:

public class FastSafeIterableMap<K, V> extends SafeIterableMap<K, V> {

    private HashMap<K, Entry<K, V>> mHashMap = new HashMap<>();

}

//继承自SafeIterableMap
public class SafeIterableMap<K, V> implements Iterable<Map.Entry<K, V>> {

    @SuppressWarnings("WeakerAccess") /* synthetic access */
    Entry<K, V> mStart;
    private Entry<K, V> mEnd;
    // using WeakHashMap over List<WeakReference>, so we don't have to manually remove
    // WeakReferences that have null in them.
    private WeakHashMap<SupportRemove<K, V>, Boolean> mIterators = new WeakHashMap<>();
    private int mSize = 0;

}

我们可以得出以下结论:
1、SafeIterableMap实现了Iterable接口,是可以迭代的。
2、SafeIterableMap并没有实现Map接口,内部维护了一个链表,这样保证了观察者之前的时序性。同时FastSafeIterableMap中有一个HashMap,可以通过key快速查找到对应的节点。
3、mStart代表头节点,mEnd代表尾节点。
4、SafeIterableMap是非线程安全的。
另外这个Map提供了三个迭代器,分别为:
1、升序迭代器AscendingIterator,迭代过程中并不包含新增的元素。
2、降序迭代器DescendingIterator,迭代过程中并不包含新增的元素。
3、迭代器IteratorWithAdditions,迭代过程中包含新增的元素。
AscendingIterator和DescendingIterator的区别在于迭代顺序的不同,两者在创建的一瞬间就已经将头节点和尾节点的指针作为参数传入迭代器了,当迭代进行到mNext == mExpectedEnd或者mExpectedEnd == null时就会结束,所以不包含后续新增的元素,具体细节可以跟跟代码。我们可以看看AscendingIterator的创建过程和迭代过程的关键方法:

public Iterator<Map.Entry<K, V>> iterator() {
        //将当前情况下的mStart头节点和mEnd尾节点传入迭代器
        ListIterator<K, V> iterator = new AscendingIterator<>(mStart, mEnd);
        mIterators.put(iterator, false);
        return iterator;
}

//迭代器AscendingIterator和DescendingIterator都是继承自它
private abstract static class ListIterator<K, V> implements Iterator<Map.Entry<K, V>>,
            SupportRemove<K, V> {
        Entry<K, V> mExpectedEnd;
        Entry<K, V> mNext;

        ListIterator(Entry<K, V> start, Entry<K, V> expectedEnd) {
            this.mExpectedEnd = expectedEnd;
            this.mNext = start;
        }

        @Override
        public boolean hasNext() {
            return mNext != null;
        }

        @SuppressWarnings("ReferenceEquality")
        private Entry<K, V> nextNode() {
            if (mNext == mExpectedEnd || mExpectedEnd == null) {
                return null;
            }
            return forward(mNext);
        }

        @Override
        public Map.Entry<K, V> next() {
            Map.Entry<K, V> result = mNext;
            mNext = nextNode();
            return result;
        }
}

而IteratorWithAdditions则是在迭代过程中包含了新元素的,它是直接从头节点一直向尾部遍历到结束的,代码如下:

private class IteratorWithAdditions implements Iterator<Map.Entry<K, V>>, SupportRemove<K, V> {
        private Entry<K, V> mCurrent;
        private boolean mBeforeStart = true;

        IteratorWithAdditions() {
        }

        @Override
        public boolean hasNext() {
            if (mBeforeStart) {
                return mStart != null;
            }
            return mCurrent != null && mCurrent.mNext != null;
        }

        @Override
        public Map.Entry<K, V> next() {
            if (mBeforeStart) {
                mBeforeStart = false;
                mCurrent = mStart;
            } else {
                mCurrent = mCurrent != null ? mCurrent.mNext : null;
            }
            return mCurrent;
        }
}

3、更新状态

调用setCurrentState时,真正调用的其实是moveToState方法,moveToState中的核心方法则为sync(),代码如下:

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;
            // no need to check eldest for nullability, because isSynced does it for us.
            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;
}

//调用isSynced()
private boolean isSynced() {
        if (mObserverMap.size() == 0) {
            return true;
        }
        State eldestObserverState = mObserverMap.eldest().getValue().mState;
        State newestObserverState = mObserverMap.newest().getValue().mState;
        return eldestObserverState == newestObserverState && mState == newestObserverState;
}

可以发现,在进行同步时会调用isSynced()方法,其内部通过判断最新和最老的观察者的状态是否都等于当前状态mState来判断是否已经同步完毕。状态往INITIALIZED->RESUMED方向变化时,调用forwardPass方法。状态往RESUMED->DESTROYED方向变化时,调用backwardPass方法。

forwardPass和backwardPass原理是相同的,只是方向不同,直接看forwardPass的代码:

private void forwardPass(LifecycleOwner lifecycleOwner) {
        Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
                mObserverMap.iteratorWithAdditions();
        while (ascendingIterator.hasNext() && !mNewEventOccurred) {
            Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next();
            ObserverWithState observer = entry.getValue();
            while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
                    && mObserverMap.contains(entry.getKey()))) {
                pushParentState(observer.mState);
                observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState));
                popParentState();
            }
        }
}

这里出现了我们刚刚提到的迭代器。逻辑也很简单,遍历观察者,逐个通知,upEvent方法的返回值是传入state的下一个事件,这意味着每个观察者收到的回调都是连续的。

4、对于事件嵌套的处理

通过上面的分析,可以发现常规情况下,有以下两种场景来更新状态:
1、新观察者注册进来
2、新状态被设置进来
考虑以下稍微复杂一些的场景:
1、在回调中发送了新的状态
2、在回调中增加了新的观察者

对于第一个场景,其实是通过mNewEventOccurred变量中断当前正在进行的同步,并且以新的状态同步。

对于第二个场景,在添加新的观察者时,有如下代码:

private State calculateTargetState(LifecycleObserver observer) {
        Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);

        State siblingState = previous != null ? previous.getValue().mState : null;
        State parentState = !mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() - 1)
                : null;
        return min(min(mState, siblingState), parentState);
}

parentState的赋值是在执行观察者的回调前,先将观察者当前状态pushParentState压入栈,在回调结束之后,popParentState出栈。
previous表示新的观察者前面的那个观察者,也就是原来的观察队列的队尾,而现在的队尾是新观察者了。可以看出State是取LifecycleRegistry当前状态,previous当前状态,parentState栈顶状态三者的最小值。这样就保证了新的观察者的状态不会大于之前的观察者的状态。

4、观察者的解注册

观察者解注册的逻辑比较简单,代码如下:

@Override
public void removeObserver(@NonNull LifecycleObserver observer) {
        mObserverMap.remove(observer);
}

至此,整个源码分析过程结束。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345