我有一个Live Android应用程序,从市场上我收到了以下堆栈跟踪,我不知道为什么它会发生,因为它不是发生在应用程序代码中,而是由应用程序的一些或其他事件引起的(假设)

我没有使用片段,仍然有一个FragmentManager的参考。 如果有人能揭示一些隐藏的事实,以避免这类问题:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1109)
at android.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:399)
at android.app.Activity.onBackPressed(Activity.java:2066)
at android.app.Activity.onKeyDown(Activity.java:1962)
at android.view.KeyEvent.dispatch(KeyEvent.java:2482)
at android.app.Activity.dispatchKeyEvent(Activity.java:2274)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1668)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1720)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1258)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1668)
at android.view.ViewRoot.deliverKeyEventPostIme(ViewRoot.java:2851)
at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2824)
at android.view.ViewRoot.handleMessage(ViewRoot.java:2011)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:132)
at android.app.ActivityThread.main(ActivityThread.java:4025)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:491)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
at dalvik.system.NativeStart.main(Native Method)  

如果你试图在你的片段活动的onSaveInstanceState()被调用后执行片段转换,就会发生这样的异常。

发生这种情况的一个原因是,当一个活动停止时,如果你让一个AsyncTask(或线程)运行。

调用onSaveInstanceState()后的任何转换都可能丢失,如果系统回收活动的资源并稍后重新创建它。


当用户旋转屏幕以便加载与新方向相关的资源时,onSaveInstance将被调用。

有可能这个用户旋转了屏幕,然后按了后退按钮(因为也有可能这个用户在使用你的应用程序时摸不着他们的手机)


这是我迄今为止遇到的最愚蠢的错误。我有一个片段应用程序工作完美的API < 11,并强制关闭API > 11。

我真的不知道他们在saveInstance调用的活动生命周期内改变了什么,但我在这里是我如何解决这个问题的:

@Override
protected void onSaveInstanceState(Bundle outState) {
    //No call for super(). Bug on API Level > 11.
}

我只是不调用.super(),一切都很好。我希望这将为您节省一些时间。

编辑:经过进一步研究,这是支持包中的一个已知错误。

如果你需要保存实例,并添加一些东西到你的outState Bundle,你可以使用以下方法:

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putString("WORKAROUND_FOR_BUG_19917_KEY", "WORKAROUND_FOR_BUG_19917_VALUE");
    super.onSaveInstanceState(outState);
}

EDIT2:如果您试图在Activity在后台消失后执行事务,也可能会发生这种情况。为了避免这种情况,你应该使用commitAllowingStateLoss()

EDIT3: The above solutions were fixing issues in the early support.v4 libraries from what I can remember. But if you still have issues with this you MUST also read @AlexLockwood 's blog : Fragment Transactions & Activity State Loss Summary from the blog post (but I strongly recommend you to read it) : NEVER commit() transactions after onPause() on pre-Honeycomb, and onStop() on post-Honeycomb Be careful when committing transactions inside Activity lifecycle methods. Use onCreate(), onResumeFragments() and onPostResume() Avoid performing transactions inside asynchronous callback methods Use commitAllowingStateLoss() only as a last resort


I solved the issue with onconfigurationchanged. The trick is that according to android activity life cycle, when you explicitly called an intent(camera intent, or any other one); the activity is paused and onsavedInstance is called in that case. When rotating the device to a different position other than the one during which the activity was active; doing fragment operations such as fragment commit causes Illegal state exception. There are lots of complains about it. It's something about android activity lifecycle management and proper method calls. To solve it I did this: 1-Override the onsavedInstance method of your activity, and determine the current screen orientation(portrait or landscape) then set your screen orientation to it before your activity is paused. that way the activity you lock the screen rotation for your activity in case it has been rotated by another one. 2-then , override onresume method of activity, and set your orientation mode now to sensor so that after onsaved method is called it will call one more time onconfiguration to deal with the rotation properly.

你可以复制/粘贴这段代码到你的活动来处理它:

@Override
protected void onSaveInstanceState(Bundle outState) {       
    super.onSaveInstanceState(outState);

    Toast.makeText(this, "Activity OnResume(): Lock Screen Orientation ", Toast.LENGTH_LONG).show();
    int orientation =this.getDisplayOrientation();
    //Lock the screen orientation to the current display orientation : Landscape or Potrait
    this.setRequestedOrientation(orientation);
}

//A method found in stackOverflow, don't remember the author, to determine the right screen orientation independently of the phone or tablet device 
public int getDisplayOrientation() {
    Display getOrient = getWindowManager().getDefaultDisplay();

    int orientation = getOrient.getOrientation();

    // Sometimes you may get undefined orientation Value is 0
    // simple logic solves the problem compare the screen
    // X,Y Co-ordinates and determine the Orientation in such cases
    if (orientation == Configuration.ORIENTATION_UNDEFINED) {
        Configuration config = getResources().getConfiguration();
        orientation = config.orientation;

        if (orientation == Configuration.ORIENTATION_UNDEFINED) {
        // if height and widht of screen are equal then
        // it is square orientation
            if (getOrient.getWidth() == getOrient.getHeight()) {
                orientation = Configuration.ORIENTATION_SQUARE;
            } else { //if widht is less than height than it is portrait
                if (getOrient.getWidth() < getOrient.getHeight()) {
                    orientation = Configuration.ORIENTATION_PORTRAIT;
                } else { // if it is not any of the above it will defineitly be landscape
                    orientation = Configuration.ORIENTATION_LANDSCAPE;
                }
            }
        }
    }
    return orientation; // return value 1 is portrait and 2 is Landscape Mode
}

@Override
public void onResume() {
    super.onResume();
    Toast.makeText(this, "Activity OnResume(): Unlock Screen Orientation ", Toast.LENGTH_LONG).show();
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
} 

在Android源代码中查找导致此问题的原因,给出FragmentManagerImpl类(Activity中可用的实例)中的标记mStateSaved的值为true。当Activity#onSaveInstanceState调用后堆栈被保存(saveAllState)时,它被设置为true。 之后,来自ActivityThread的调用不会使用FragmentManagerImpl#noteStateNotSaved()和dispatch()中的可用重置方法重置该标志。

在我看来,有一些可用的修复,这取决于你的应用程序正在做什么和使用:

的好方法

首先,我要为Alex Lockwood的文章做广告。然后,根据我目前所做的:

For fragments and activities that don't need to keep any state information, call commitAllowStateLoss. Taken from documentation: Allows the commit to be executed after an activity's state is saved. This is dangerous because the commit can be lost if the activity needs to later be restored from its state, so this should only be used for cases where it is okay for the UI state to change unexpectedly on the user`. I guess this is alright to use if the fragment is showing read-only information. Or even if they do show editable info, use the callbacks methods to retain the edited info. Just after the transaction is commit (you just called commit()), make a call to FragmentManager.executePendingTransactions().

不推荐的方法:

As Ovidiu Latcu mentioned above, don't call super.onSaveInstanceState(). But this means you will lose the whole state of your activity along with fragments state. Override onBackPressed and in there call only finish(). This should be OK if you application doesn't use Fragments API; as in super.onBackPressed there is a call to FragmentManager#popBackStackImmediate(). If you are using both Fragments API and the state of your activity is important/vital, then you could try to call using reflection API FragmentManagerImpl#noteStateNotSaved(). But this is a hack, or one could say it's a workaround. I don't like it, but in my case it's quite acceptable since I have a code from a legacy app that uses deprecated code (TabActivity and implicitly LocalActivityManager).

下面是使用反射的代码:

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    invokeFragmentManagerNoteStateNotSaved();
}

@SuppressWarnings({ "rawtypes", "unchecked" })
private void invokeFragmentManagerNoteStateNotSaved() {
    /**
     * For post-Honeycomb devices
     */
    if (Build.VERSION.SDK_INT < 11) {
        return;
    }
    try {
        Class cls = getClass();
        do {
            cls = cls.getSuperclass();
        } while (!"Activity".equals(cls.getSimpleName()));
        Field fragmentMgrField = cls.getDeclaredField("mFragments");
        fragmentMgrField.setAccessible(true);

        Object fragmentMgr = fragmentMgrField.get(this);
        cls = fragmentMgr.getClass();

        Method noteStateNotSavedMethod = cls.getDeclaredMethod("noteStateNotSaved", new Class[] {});
        noteStateNotSavedMethod.invoke(fragmentMgr, new Object[] {});
        Log.d("DLOutState", "Successful call for noteStateNotSaved!!!");
    } catch (Exception ex) {
        Log.e("DLOutState", "Exception on worka FM.noteStateNotSaved", ex);
    }
}

干杯!


读 http://chris-alexander.co.uk/on-engineering/dev/android-fragments-within-fragments/

篇文章。 fragment. isresume()检查帮助我在onDestroyView w/o使用onSaveInstanceState方法。


这对我很管用……我自己发现的…希望对你有所帮助!

1)不要有全局的“静态”FragmentManager / FragmentTransaction。

2) onCreate,总是初始化FragmentManager再次!

样本如下:-

public abstract class FragmentController extends AnotherActivity{
protected FragmentManager fragmentManager;
protected FragmentTransaction fragmentTransaction;
protected Bundle mSavedInstanceState;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mSavedInstanceState = savedInstanceState;
    setDefaultFragments();
}

protected void setDefaultFragments() {
    fragmentManager = getSupportFragmentManager();
    //check if on orientation change.. do not re-add fragments!
    if(mSavedInstanceState == null) {
        //instantiate the fragment manager

        fragmentTransaction = fragmentManager.beginTransaction();

        //the navigation fragments
        NavigationFragment navFrag = new NavigationFragment();
        ToolbarFragment toolFrag = new ToolbarFragment();

        fragmentTransaction.add(R.id.NavLayout, navFrag, "NavFrag");
        fragmentTransaction.add(R.id.ToolbarLayout, toolFrag, "ToolFrag");
        fragmentTransaction.commitAllowingStateLoss();

        //add own fragment to the nav (abstract method)
        setOwnFragment();
    }
}

我对这个问题的解决方案是

在片段中添加方法:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    ...
    guideMapFragment = (SupportMapFragment)a.getSupportFragmentManager().findFragmentById(R.id.guideMap);
    guideMap = guideMapFragment.getMap();
    ...
}

@Override
public void onDestroyView() {
    SherlockFragmentActivity a = getSherlockActivity();
    if (a != null && guideMapFragment != null) {
        try {
            Log.i(LOGTAG, "Removing map fragment");
            a.getSupportFragmentManager().beginTransaction().remove(guideMapFragment).commit();
            guideMapFragment = null;
        } catch(IllegalStateException e) {
            Log.i(LOGTAG, "IllegalStateException on exit");
        }
    }
    super.onDestroyView();
}

可能很糟糕,但找不到更好的了。


Android 4.2和支持库的源代码中修正了这个问题。[*]

有关原因(和解决方案)的详细信息,请参阅谷歌错误报告: http://code.google.com/p/android/issues/detail?id=19917

如果你正在使用支持库,那么你不应该担心这个错误(很长时间)[*]。然而,如果你直接使用API(即不使用支持库的FragmentManager),并针对Android 4.2以下的API,那么你将需要尝试一种变通方法。

[*]在撰写本文时,Android SDK管理器仍在分发显示此错误的旧版本。

编辑,我要在这里补充一些澄清,因为我显然把投票反对这个答案的人弄糊涂了。

There are several different (but related) circumstances that can cause this exception to be thrown. My answer above is referring to the specific instance discussed in the question i.e. a bug in Android which has subsequently been fixed. If you're getting this exception for another reason it's because you're adding/removing fragments when you shouldn't be (after fragment states have been saved). If you're in such a situation then perhaps "Nested Fragments - IllegalStateException “Can not perform this action after onSaveInstanceState”" can be of use to you.


只需在显示你的片段之前调用super.onPostResume(),或者在调用super.onPostResume()之后在onPostResume()方法中移动你的代码。这就解决了问题!


好吧,在尝试了以上所有的解决方案都没有成功(因为基本上我没有事务)。

在我的情况下,我使用alertdialog和ProgressDialog作为片段,有时,在旋转时,当请求FragmentManager时,错误会上升。

我找到了一个混合了许多类似帖子的变通方法:

这是一个3步解决方案,所有在你的FragmentActivity(在这种情况下,它被称为GenericActivity):

private static WeakReference<GenericActivity> activity = null; //To avoid bug for fragments: Step 1 of 3

@Override
protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    //To avoid bug for fragments: Step 2 of 3
    activity = new WeakReference<GenericActivity>(this);
}

@Override
public FragmentManager getSupportFragmentManager(){
    //To avoid bug for fragments: Step 3 of 3
    if (this == activity.get()) {
        return super.getSupportFragmentManager();
    }
    return activity.get().getSupportFragmentManager();
}

在屏幕被锁定\blank并且Activity +对话框的实例状态被保存之后,在对话框片段上调用dismiss()也会发生这种情况。要绕过这个调用:

dismissAllowingStateLoss()

实际上,每次我解散一个对话框时,我都不再关心它的状态了,所以这样做是可以的——实际上你并没有失去任何状态。


当我在一个片段中使用startactivity时,我会得到这个异常;

当我改变使用startactivityforresult时,异常消失了:)

所以修复它的简单方法是使用startActivityForResult api:)


我得到这个异常时,我按下后退按钮取消意图选择器在我的地图片段活动。 我通过替换onResume()的代码来解决这个问题(我在那里初始化片段和提交事务)到onStart(),应用程序现在工作正常。 希望能有所帮助。


你可以使用FragmentActivity。onStart在popBackStackImmediate之前

是这样的:

public void backStackFragment() {
    this.start();
    getFragmentManager().popBackStackImmediate();
}

public void start(){
    FragmentActivity a = getActivity();
    if(a instanceof DepositPlanPadActivity){
      ((DepositPlanPadActivity)a).onStart();
    }
    if(a instanceof SmallChangePlanPad){
            ((SmallChangePlanPad)a).onStart();
        }
        if(a instanceof UserCenterActivity){
            ((UserCenterActivity)a).onStart();
        }
    }

http://jorryliu.blogspot.com/2014/09/illegalstateexception-can-not-perform.html


简单有效的解决方案:

遵循简单的步骤:

步骤1:在各自的片段中覆盖onSaveInstanceState状态。并从中移除super method。

@Override
public void onSaveInstanceState(Bundle outState) {
};

步骤2:使用CommitAllowingStateLoss();而不是commit();而片段操作。

fragmentTransaction.commitAllowingStateLoss();

当我试图在onActivityForResult()方法中显示片段时,我总是得到这个,所以接下来的问题是:

我的活动暂停和停止,这意味着,onSaveInstanceState()已经被调用(对于pre-Honeycomb和post-Honeycomb设备)。 在任何结果的情况下,我使事务显示/隐藏片段,这导致这个IllegalStateException。

接下来我做的是:

增加了确定我想要的动作是否完成的值(例如,从camere - isPhotoTaken中拍摄照片)-它可以是布尔值或整数值,这取决于你需要多少不同的事务。 在重写onResumeFragments()方法中,我检查了我的值,并在我需要的片段事务之后。在这种情况下,commit()没有在onSaveInstanceState之后执行,因为状态是在onResumeFragments()方法中返回的。


经过研究,这个问题的解决方案是做你的片段提交在onresume。

来源:https://wenchaojames.wordpress.com/2013/01/12/illegalstateexception-from-onactivityresult/


我有同样的问题,得到IllegalStateException,但替换所有调用commit()与commitAllowingStateLoss()没有帮助。

罪魁祸首是调用DialogFragment.show()。

我用

try {
    dialog.show(transaction, "blah blah");
}
catch(IllegalStateException e) {
    return;
}

这样就成功了。好吧,我没有展示对话,但在这种情况下,这是可以的。

这是我的应用程序中唯一一个我第一次调用FragmentManager.beginTransaction()但从未调用commit()的地方,所以当我寻找“commit()”时,我没有找到它。

有趣的是,用户从未离开该应用。相反,出现的AdMob插页广告才是罪魁祸首。


我也有同样的问题,经过一天的分析,所有的文章,博客和stackoverflow,我找到了一个简单的解决方案。完全不要使用savedInstanceState,这是一行代码的条件。在片段代码上:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(null);
    .....

我有这个问题。但是我认为这个问题与commit和commitAllowStateLoss无关。

下面的堆栈跟踪和异常消息是关于commit()的。

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1341)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1352)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)

但是这个异常是由onBackPressed()引起的

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(Unknown Source)
at android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(Unknown Source)
at android.support.v4.app.FragmentActivity.onBackPressed(Unknown Source)

它们都是由checkStateLoss()引起的

private void checkStateLoss() {
    if (mStateSaved) {
        throw new IllegalStateException(
                "Can not perform this action after onSaveInstanceState");
    }
    if (mNoTransactionsBecause != null) {
        throw new IllegalStateException(
                "Can not perform this action inside of " + mNoTransactionsBecause);
    }

mStateSaved在onSaveInstanceState之后为真。

这个问题很少发生。我从来没有遇到过这个问题。我不能再出现这个问题。

我找到了25517号

它可能在下列情况下发生

Back键在onSaveInstanceState之后,但在新活动开始之前被调用。 在代码中使用onStop()

我不确定问题的根源是什么。 所以我用了一个丑陋的方法。

@Override
public void onBackPressed() {

    try{
        super.onBackPressed();
    }catch (IllegalStateException e){
        // can output some information here
        finish();
    }
}

My use case: I have used listener in fragment to notify activity that some thing happened. I did new fragment commit on callback method. This works perfectly fine on first time. But on orientation change the activity is recreated with saved instance state. In that case fragment is not created again implies that the fragment have the listener which is old destroyed activity. Any way the call back method will get triggered on action. It goes to destroyed activity which cause the issue. The solution is to reset the listener in fragment with current live activity. This solve the problem.


我发现,如果另一个应用程序是对话类型,并允许触摸被发送到后台应用程序,那么几乎任何后台应用程序都会崩溃与此错误。 我认为我们需要在每次执行事务时检查实例是否保存或恢复。


在我的例子中,有相同的错误异常,我把“onBackPressed()”放在一个可运行对象中(你可以使用你的任何视图):

myView.post(new Runnable() {
                    @Override
                    public void run() {
                        onBackPressed()
                    }
                });

我不知道为什么,但它有效!


我在我的应用程序中有同样的问题。我已经解决了这个问题,只是调用super.onBackPressed();并在当前类上调用commitAllowingStateLoss()。


你可能会调用fragmentManager.popBackStackImmediate();当活动暂停时。活动未完成,但处于暂停状态,且不在前台。你需要在popBackStackImmediate()之前检查activity是否被暂停。


我认为在这些操作之前调用FragmentActivity.onStateNotSaved()可能是目前最好的选择。


谢谢@gunar,但我认为有更好的方法。

医生说:

*如果您提交的单个事务没有修改 *碎片回栈,强烈考虑使用 * {@link FragmentTransaction#commitNow()}代替。这有助于避免 *当应用程序中的其他代码未提交时,会产生不必要的副作用 *需要不同时间的事务。 * * @return如果有任何待处理事务则返回true *执行。 * / executePendingTransactions();

所以使用commitNow替换:

fragmentTransaction.commit();
FragmentManager.executePendingTransactions()

这发生在你试图加载一个片段,但活动已改变其状态为onPause()。例如,当您试图获取数据并将其加载到活动中,但当用户单击某个按钮并移动到下一个活动时,就会发生这种情况。

你可以用两种方法解决这个问题

您可以使用transaction.commitAllowingStateLoss()而不是transaction.commit()来加载片段,但您可能最终会丢失已完成的提交操作。

or

在加载片段时,确保活动处于恢复状态,而不是进入暂停状态。 创建一个布尔值并检查activity是否不进入onPause()状态。

@Override
public void onResume() {
    super.onResume();
    mIsResumed = true;
}

@Override
public void onPause() {
    mIsResumed = false;
    super.onPause();
}

然后,而加载片段检查活动是否存在,只有当活动是前景时才加载。

if(mIsResumed){
 //load the fragment
}

I noticed something very interesting. I have in my app the option to open the phone's gallery and the device asks what app to use, there I click on the gray area away from the dialog and saw this issue. I noticed how my activity goes from onPause, onSaveInstanceState back to onResume, it doesn't happen to visit onCreateView. I am doing transactions at onResume. So what I ended up doing is setting a flag being negated onPause, but being true onCreateView. if the flag is true onResume then do onCommit, otherwise commitAllowingStateLoss. I could go on and waste so much time but I wanted to check the lifecycle. I have a device which is sdkversion 23, and I don't get this issue, but I have another one which is 21, and there I see it.


我认为生命周期状态可以帮助防止这种崩溃从Android支持库v26.1.0开始,你可以有以下检查:

if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)){
  // Do fragment's transaction commit
}

或者你可以试试:

Fragment.isStateSaved()

更多信息请点击这里 https://developer.android.com/reference/android/support/v4/app/Fragment.html isStateSaved ()


解决这个问题的另一种生命周期方法是使用kotlin最新发布的lifecycle-ktx。

lifecycleScope.launchWhenResumed {
    // your code with fragment or dialogfragment
}

闭包将在恢复状态后运行,因此甚至在恢复状态后调用此方法 停,等下一份简历来的时候就安全执行了。

你也可以选择喜欢

lifecycleScope.launchWhenCreated
// or
lifecycleScope.launchWhenStarted

适合你的情况。

当销毁完成时,代码将被取消。

谷歌文档链接: https://developer.android.com/kotlin/ktx#lifecycle


当一个Fragment或AppCompatActivity的状态通过onSaveInstanceState()保存时,它的UI被认为是不可变的,直到ON_START被调用。在保存状态后尝试修改UI可能会导致应用程序导航状态的不一致,这就是为什么FragmentManager会抛出异常,如果应用程序在保存状态后运行FragmentTransaction。参见commit()了解详细信息。

LiveData通过避免在观察者的关联生命周期至少不是STARTED时调用它的观察者来避免这种边缘情况。在幕后,它在决定调用其观察者之前调用isAtLeast()。