Lifecycle源码分析4 -- LifecycleRegistry源码解析

·  阅读 826

前言

我们继续来分析LifecycleRegistry源码,前面文章没有看过的可以查看:

Lifecycle源码分析1 -- Lifecycle的介绍以及简单使用 - 掘金 (juejin.cn)

Lifecycle源码分析2 -- Lifecycle的生命周期事件如何获取 - 掘金 (juejin.cn)

Lifecycle源码分析3 -- LifecycleRegistry概述和FastSafeIterableMap分析 - 掘金 (juejin.cn)

正文

LifecycleRegistry作为Lifecycle的实现类,它的作用便是处理Event、分发Event以及保存Lifecycle的状态,但是这其中涉及到了2个事件发送的嵌套,所以我们挨个来说说。

构造函数

看一下构造函数:

public LifecycleRegistry(@NonNull LifecycleOwner provider) {
    this(provider, true);
}

//分别保存owner和state,确保操作在主线程
private LifecycleRegistry(@NonNull LifecycleOwner provider, boolean enforceMainThread) {
    mLifecycleOwner = new WeakReference<>(provider);
    mState = INITIALIZED;
    mEnforceMainThread = enforceMainThread;
}
复制代码

构造函数可以注意3点:

1、 LifecycleOwner使用弱引用,这样可以方便Activity或者Fragment进行垃圾回收。

2、 Lifecycle的初始状态是INITIALIZED状态。

3、 必须在主线程。

处理Event

下面方法在前面文章说过,Activity/Fragment会调用这个函数来处理生命周期事件回调

public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
    enforceMainThreadIfNeeded("handleLifecycleEvent");
    moveToState(event.getTargetState());
}
复制代码

看一下这个event.getTargetState方法:

@NonNull
//这里根据发生的事件,获取接下来的状态
public State getTargetState() {
    switch (this) {
        case ON_CREATE:
        case ON_STOP:
            return State.CREATED;
        case ON_START:
        case ON_PAUSE:
            return State.STARTED;
        case ON_RESUME:
            return State.RESUMED;
        case ON_DESTROY:
            return State.DESTROYED;
        case ON_ANY:
            break;
    }
    throw new IllegalArgumentException(this + " has no target state");
}
复制代码

上面根据Event获取对应的State必须要熟悉,比如ON_CREATE和ON_STOP后都是CREATED状态,切换效果如下:

image.png

接着看一下关键代码也就是moveToState方法:

//转换状态
private void moveToState(State next) {
    if (mState == next) {
        return;
    }
    //直接赋值到新状态
    mState = next;
    //当正在处理事件或者正在增加观察者时,不继续处理
    if (mHandlingEvent || mAddingObserverCounter != 0) {
        //新的事件已经发生
        mNewEventOccurred = true;
        return;
    }
    //正在处理事件
    mHandlingEvent = true;
    //同步事件
    sync();
    mHandlingEvent = false;
}
复制代码

这里有几个标志位,它的作用我们继续看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;
        //当当前状态小于观察者链表最开始节点的状态,进行回退
        if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
            //回退和分发状态
            backwardPass(lifecycleOwner);
        }
        //当当前状态大于观察者链表最后节点的状态且没有在新增事件时,进行向前
        Map.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;
}
复制代码

这里同步完成的条件比较苛刻,但是也是必须的,那什么时候会出现链表里的各个节点状态不一样呢,也就是进行回退或者前进状态的时候,直接看源码:

//回退状态,也就是回退观察者列表里所有节点的状态
private void backwardPass(LifecycleOwner lifecycleOwner) {
    //倒序遍历
    Iterator<Map.Entry<LifecycleObserver, ObserverWithState>> descendingIterator =
            mObserverMap.descendingIterator();
    //当有新事件出现时停止操作
    while (descendingIterator.hasNext() && !mNewEventOccurred) {
        Map.Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next();
        ObserverWithState observer = entry.getValue();
        //当该节点状态大于预期状态
        while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred
                && mObserverMap.contains(entry.getKey()))) {
            //降级处理
            Event event = Event.downFrom(observer.mState);
            if (event == null) {
                throw new IllegalStateException("no event down from " + observer.mState);
            }
            //细节,后面细说
            pushParentState(event.getTargetState());
            //分发事件且同时对observer保存的state进行修改
            observer.dispatchEvent(lifecycleOwner, event);
            popParentState();
        }
    }
}
复制代码

会发现回退里面居然有2个while循环,第一个很好理解是遍历所有,第二个是为啥呢 因为这里降级只能一级一级降低,我们看一下downFrom函数:

//对状态进行降级处理
public static Event downFrom(@NonNull State state) {
    switch (state) {
        case CREATED:
            return ON_DESTROY;
        case STARTED:
            return ON_STOP;
        case RESUMED:
            return ON_PAUSE;
        default:
            return null;
    }
}
复制代码

所以可能是该节点状态是RESUMED,但是期望状态是CREATED,就需要降级2次才可以。

到这里回退的大致流程就说完了,我们接着来举例说一下这个标志位的作用。

大致流程

假如现在Activity处于用户可见可点击状态,也就是ON_RESUME状态,且有4个观察者,且已经同步完成,那4个观察者的状态便是:

4 -> 4 -> 4 -> 4

这里4就是表示State.RESUMED状态,然后这时Activity不可见,这时会触发onPause事件,然后会把ON_PAUSE通过getTargetState方法获取是STARTED状态,然后需要进行回退降级处理,在sync方法中会发现isSynced方法返回false,然后还会发现STARTED即3小于链表最开始的4,所以要回退,在回退中依然保证该列表的特性:链表后面节点的状态不能大于前面的,所以回退步骤是:

4 -> 4 -> 4 -> 3

4 -> 4 -> 3 -> 3

4 -> 3 -> 3 -> 3

3 -> 3 -> 3 -> 3

这里结束同步。

同步过程新事件产生

上面是理想状态,而且同步过程当观察者很多的时候,就会非常耗时,所以在同步过程中可能会发现moveToState又被调用了,也就是新事件来了,代码中的:

mNewEventOccurred
复制代码

这个标志位,也就是当这个标志位为true时,就及时打断同步过程,而使用新的state进行同步,这样可以节约时间。

关于其他标志位我们后面再说。

添加观察者

我们说完了假如该Lifecycle有多个观察者是如何处理新事件的,那接着就捋一下添加观察者时,LifecycleRegistry为我们做了什么,直接看代码:

@Override
public void addObserver(@NonNull LifecycleObserver observer) {
    enforceMainThreadIfNeeded("addObserver");
    //刚添加进来的观察者状态默认就是INITIALIZED
    State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
    ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
    //是否已经有这个观察者了
    ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

    if (previous != null) {
        return;
    }
    LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
    if (lifecycleOwner == null) {
        // it is null we should be destroyed. Fallback quickly
        return;
    }
    //判断是否正在添加或者正在处理事件
    boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
    //计算当前新添加的observer目标状态
    State targetState = calculateTargetState(observer);
    mAddingObserverCounter++;
    //当 期望状态小于目标状态
    while ((statefulObserver.mState.compareTo(targetState) < 0
            && mObserverMap.contains(observer))) {
        //细节 后面说
        pushParentState(statefulObserver.mState);
        //状态升级
        final Event event = Event.upFrom(statefulObserver.mState);
        if (event == null) {
            throw new IllegalStateException("no event up from " + statefulObserver.mState);
        }
        //分发事件
        statefulObserver.dispatchEvent(lifecycleOwner, event);
        popParentState();
        //再次计算
        targetState = calculateTargetState(observer);
    }

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

这里代码其实很简单,还是先考虑事件不重叠的情况,假如原来的观察者还是4个分别是:

4 -> 4 -> 4 -> 4

这时添加进来一个观察者,其默认状态是1,那么期望状态是4,所以调用upFrom方法:

//提升状态
@Nullable
public static Event upFrom(@NonNull State state) {
    switch (state) {
        case INITIALIZED:
            return ON_CREATE;
        case CREATED:
            return ON_START;
        case STARTED:
            return ON_RESUME;
        default:
            return null;
    }
}
复制代码

而这个步骤也是一步一步提升:

4 -> 4 -> 4 -> 4 -> 1

4 -> 4 -> 4 -> 4 -> 2

4 -> 4 -> 4 -> 4 -> 3

4 -> 4 -> 4 -> 4 -> 4

到这里,添加介绍,而且状态也同步正确。

这里有个点需要注意,当新观察者从1提升到4的过程中,是有分发事件的,所以这就是Lifecycle的又一个定律:当新的观察者被添加进来时,Lifecycle将会把之前的Event都回调一遍

事件嵌套

现在可以说事件嵌套了,也就是处理分发事件和添加观察者之间的嵌套。

当处理分发事件时又来了新事件

这个在前面说过了,由于同步非常耗时,需要遍历链表且一步一步提升,所以有了mNewEventOccurred这个标志位来及时打断这个循环,使用新的State来同步。

当添加观察者时又来了观察者或者处理事件

这个就是在上面添加observer的代码中的mAddingObserverCounter和mHandlingEvent这2个标志位来控制,当处于正常状态时才进行同步,这样也可以减少同步代码的执行时间。

复杂的mParentStates

在添加observer中获取明白target时,有下面代码:

//计算明白状态
private State calculateTargetState(LifecycleObserver observer) {
    //获取链表前一个节点
    Map.Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);

    State siblingState = previous != null ? previous.getValue().mState : null;
    //获取parentState最后一个节点
    State parentState = !mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() - 1)
            : null;
    //当前保存的state 这3个取最小值
    return min(min(mState, siblingState), parentState);
}
复制代码

而这个mParentStates的操作如下:

//定义
private ArrayList<State> mParentStates = new ArrayList<>();
复制代码
private void popParentState() {
    mParentStates.remove(mParentStates.size() - 1);
}

private void pushParentState(State state) {
    mParentStates.add(state);
}
复制代码

当在同步事件时会push和pop上面2个方法,那这个到底有什么意义呢

首先是state的准确性,这个会在什么时候不准确呢 也就是当新事件发生时,观察者列表还没有更新的时候,那我这时获取列表前一个呢,这个不就百分之百可以吗 也有一个极端个例,在源码中也有注释:

void onStart() {
    mRegistry.removeObserver(this);
     mRegistry.add(newObserver);
 }
复制代码

这种移除了链表中唯一一个观察者,再添加一个观察者,这时就有问题了,链表为空,没有前一个节点,所以这个标志位就是为了解决这个问题。

事件嵌套的逻辑还是蛮复杂的,Lifecycle设计成这样的主要目的就是能让在迭代列表时尽快完成,不做不必要的资源浪费。

总结

LifecycleRegistry的源码主要部分也就说完了,其中主要部分也就是处理事件和添加观察者,关于这2个事件的嵌套细节其实可以不用探讨那么深入。

所有的LifecycleRegistry可以总结以下几点:

  • 所有添加进来的观察者都会保存在一个有序列表中,它是一个链表实现的map,可以确保后添加进来的观察者状态不能大于之前的。

  • 处理Event事件时,会挨个遍历取提升或者降低观察者状态,同时通知观察者。

  • 添加新的观察者时,初始状态是INIT,需要不断的提升状态,会通知回调观察者多次。

  • 当这俩者嵌套发生时,要分情况处理,减少不必要循环。

这一部分其实还有一个点需要仔细说一下的,也就是它的回调事件处理,很值得我们学习,等后面文章继续来说。

分类:
Android
收藏成功!
已添加到「」, 点击更改