记录一个LifeCycle 错误使用导致 的BUG

关键字

  • lifecycle
  • 多线程
  • java.lang.IllegalArgumentException
  • bug
  • android
  • androidx

问题描述

在调用 getLifecycle().addObserver() 的时候报出这样的错误

java.lang.IllegalArgumentException  
at androidx.lifecycle.LifecycleRegistry.upEvent(SourceFile:279)  
at androidx.lifecycle.LifecycleRegistry.forwardPass(SourceFile:293)  
at androidx.lifecycle.LifecycleRegistry.sync(SourceFile:333)  
at androidx.lifecycle.LifecycleRegistry.addObserver(SourceFile:189)  

问题定位

问题代码出现在这里 LifecycleRegisty 这个类中,代码如下

  private static Event upEvent(State state) {
        switch (state) {
            case INITIALIZED:
            case DESTROYED:
                return ON_CREATE;
            case CREATED:
                return ON_START;
            case STARTED:
                return ON_RESUME;
            case RESUMED:
                throw new IllegalArgumentException();
        }
        throw new IllegalArgumentException("Unexpected state value " + state);
    }

当传入的状态是 RESUMED 的时候可以就会抛出错误,而调用这个方法的代码如下

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

        if (previous != null) {
            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(mLifecycleOwner, 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--;
    }

因为在 State 是个枚举类型 ,RESUME 排在最后,所以是最大的

public enum State {
        // 删除了无用注释
        DESTROYED,
        INITIALIZED,
        CREATED,
        STARTED,
        RESUMED;
    }

也就是说,以下代码中

 while ((statefulObserver.mState.compareTo(targetState) < 0&& mObserverMap.contains(observer))) {
            pushParentState(statefulObserver.mState);
            statefulObserver.dispatchEvent(mLifecycleOwner, upEvent(statefulObserver.mState));
            popParentState();
            // mState / subling may have been changed recalculate
            targetState = calculateTargetState(observer);
        }
}

如果你想进入循环并且满足调用 upEvent() 发生崩溃的 statefulObserver.mState 值是不存在的,因为 upEvent()需要 statefulObserver.mState的值等于RESUMED , 但是 statefulObserver.mState.compareTo(targetState) < 0 这个刚好就不能是这个条件,RESUMED 是最大的 state 值,是不可能存在其他值比较之后小于0的。

当出现这种前后矛盾的时候,大概率就是多线程调用导致了

这个时候我们就要开始找,还有什么别的方法会导致 statefulObserver.mState 的改变,通过 IDE 的 find usage 可以轻松找到 mState 修改只有下图中的两处
记录一个LifeCycle 错误使用导致 的BUG_第1张图片
排除 addObserver,重心放在 forwardPassbackwardPass ,他们统一调用的方法就是 sync,通过断点调试就能发现LifeCycleOwner 生命周期改变的时候会调用这个方法。也就是说,如果我使用非UI线程调用 addOboserver 同时改变生命周期就能达到崩溃的条件

我们在两个地方设置断点,分别是
记录一个LifeCycle 错误使用导致 的BUG_第2张图片

然后在 onResume 增加代码

override fun onResume(){
    super.onResume()
    Thread { lifecycle.addObserver(new ObserverImp()) }.start()
}

因为出错的状态是 RESUMED, 所以你只要 RESUMED 的时候加入 Oboserver 才能得到生命周期报错。操作路径是 App 后台返回前台显示,然后你就会看到
记录一个LifeCycle 错误使用导致 的BUG_第3张图片

两个线程的显示不是一开始就有的,需要点多几下过,因为需要生命周期调用 addObserver 之后才会开始新线程

这个时候我们只需要操作 UI 线程停在 RESUME 即可,如下图
记录一个LifeCycle 错误使用导致 的BUG_第4张图片

这个时候我们切换到另外一个线程, statefulObserver.mState 值就是 RESUME
记录一个LifeCycle 错误使用导致 的BUG_第5张图片
这个时候点击下一步就是崩溃了。

修复方案

  1. 增加不是主线程 addObserer 检查(用于防止事情再次发生)
  2. 移动非主线程代码到主线程中

小结

条件矛盾大概率是线程问题,剩下就是怎么构造多线程修改条件。

你可能感兴趣的:(android,lifecycle,bug,多线程)