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

我没有使用Fragments,但仍然有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)  


评论

您找到解决方案了吗?这里有相同的问题:stackoverflow.com/questions/7575921/…

我遇到了同样的问题,找到了一个适用于我的简单解决方案

@phlebas不,你没有。您关心的是对话框,而事实并非如此。堆栈跟踪匹配的顶行还不够。其余的非常不同。我之所以这样说,是因为我只是看了你的问题,不幸的是这对我没有帮助。

您在该活动中使用Thread还是AsyncTask?

我会在我的博客文章中讨论此错误...您应该阅读它。 :)

#1 楼

这是到目前为止我遇到的最愚蠢的错误。我有一个适用于API <11的Fragment应用程序,并且适用于API> 11的Force Closing应用程序。

我真的无法弄清它们在Activity生命周期中的变化,但我在这里我是如何解决这个问题的:

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


我只是不拨打saveInstance,所以一切正常。我希望这可以节省您一些时间。

编辑:经过更多研究,这是支持包中的已知错误。

如果您需要保存实例,并向其中添加一些内容,则可以使用以下命令:

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


EDIT2:这可能如果您在后台退出.super()后尝试执行事务,也会发生这种情况。为避免这种情况,您应该使用outState

EDIT3:根据我的记忆,上述解决方案已解决了早期support.v4库中的问题。但是,如果您仍然对此有疑问,还必须阅读@AlexLockwood的博客:碎片事务和活动状态丢失

博客文章的摘要(但我强烈建议您阅读):
永远不要在蜂巢之前的Bundle和蜂巢之后的Activity之后的commitAllowingStateLoss()事务
commit()生命周期方法内提交事务时要小心。使用onPause()onStop()Activity

避免在异步回调方法中执行事务
仅将onCreate()用作最后的选择


评论


您应该使用commitAllowingStateLoss()而不是commit()

–meh
2012年9月28日上午10:04

因此,如果在onSaveInstanceState中不调用super,将使FragmentManager能够保存所有片段的状态并还原它们。这可能会导致旋转问题。另外,我还尝试了将垃圾放入捆绑包的另一件事,这对我来说没有任何区别。不确定如何处理-您在支持包中引用的错误是NullPointerException,并且看起来不太像此IllegalStateException ...

–themightyjon
2012年11月7日在16:48

@meh commitAllowingStateLoss()仅避免异常。它不能保护您的应用程序免受意外状态损失。请参阅此博客文章。

– Alex Lockwood
13年8月20日在23:20

@AlexLockwood,因此从该博客文章中我们可以了解到,我们应该在该片段内进行所有网络调用(并在需要时显示一些临时进度ui),这是避免在提交时可能发生此异常的唯一方法,因为提交在一些异步方法调用之后被调用。

–meh
13年8月21日在21:30



我不明白第一点:“在蜂窝后... onStop()之后,永远不要提交()事务”。如果我需要一个按钮来触发一个片段被另一个片段替换怎么办?我是否应该放一个布尔值来检查活动是否已完成onStop,如果完成,则调用commitAllowingStateLoss?另外,如果片段中有片段,那么单击按钮时需要替换该片段怎么办?

– Android开发人员
2015年9月21日在10:13

#2 楼

查看导致此问题的原因的Android源代码会得出FragmentManagerImpl类(活动中可用的实例)中的标志mStateSaved的值为true。当在从Activity#onSaveInstanceState进行的调用中保存了后向堆栈(saveAllState)时,将其设置为true。看到它有一些可用的修复程序,具体取决于您的应用程序正在执行的操作和使用的方法:
好的方法
在进行其他操作之前:我会宣传Alex Lockwood的文章。然后,从我到目前为止所做的事情开始:


对于不需要保留任何状态信息的片段和活动,请调用commitAllowStateLoss。摘自文档:

允许保存活动状态后执行提交。这很危险,因为如果以后需要将活动从其状态还原,则提交可能会丢失,因此仅应在UI状态可以在用户上意外更改的情况下使用。我想如果片段显示只读信息就可以使用。甚至即使它们确实显示了可编辑的信息,也可以使用回调方法来保留已编辑的信息。



就在提交事务之后(您刚刚称为FragmentManagerImpl#noteStateNotSaved()),请致电dispatch()


不建议使用的方法:


如上述Ovidiu Latcu所述,请勿致电commit()。但这意味着您将丢失活动的整个状态以及碎片状态。


覆盖FragmentManager.executePendingTransactions(),在此仅调用super.onSaveInstanceState()。如果您的应用程序不使用Fragments API,这应该可以;就像在onBackPressed中一样,有一个对finish()的调用。


如果同时使用Fragments API和活动状态为重要/重要状态,则可以尝试使用反射API super.onBackPressed进行调用。但这是一种黑客手段,或者可以说这是一种解决方法。我不喜欢它,但是就我而言,这是可以接受的,因为我有一个来自旧版应用程序的代码,该代码使用了已弃用的代码(FragmentManager#popBackStackImmediate()和隐式FragmentManagerImpl#noteStateNotSaved())。使用反射的内容:
@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);
    }
}

干杯!

评论


在Gingerbread下,这似乎也发生在ActionBarSherlock上,因此检查Build Id的情况似乎没有意义... :(

–t0mm13b
13年2月28日在16:51

另外,您应该指出-这也不适合ABS使用:)

–t0mm13b
13年2月28日在17:08

@ t0mm13b:上面的代码代表我的项目,因为它既不使用片段,也不使用support.FragmentActivity。它在android.app.Activity上运行,并且由于触发Exception的不一致是由FragmentManager(API级别11向上)引起的,因此这就是检查的原因...如果您认为邪恶的源头也与您相同,请放心删除支票。 ABS是一个不同的故事,因为它运行在兼容性包和支持的实现之上.FragmentActivity可能使用FragmentManager和voila的相同实现:相同的问题。

– Gunar
13年2月28日在21:29

@ t0mm13b:要添加更多的字符(600个字符)还不够,您必须首先调查真正导致此字符的原因。您还必须意识到,上面是一个丑陋的hack,如果它运行与否,我不承担任何责任(对我而言,这是考虑到情况的最佳解决方案)。如果必须使用它,请仔细检查compat源代码中的变量命名,因为它们可能与标准软件包不同。我希望兼容性软件包的下一个版本能够解决此问题,但是从Android经验来看,发生这种情况的机会很少...

– Gunar
13年2月28日在21:34

嗯...这与此错误报告中的问题完全相同,这是此OP问题的重点。我支持我的评论-您应该明确声明免责声明,并表示不能保证,还应该声明您未使用片段-否则为什么还要麻烦发布答案! :)只是说...

–t0mm13b
13年2月28日在21:50

#3 楼

如果您在片段活动的onSaveInstanceState()被调用后尝试执行片段过渡,则会发生此类异常。

发生这种情况的一个原因是,如果在活动停止时让AsyncTask(或Thread)运行,则保持不变。

调用onSaveInstanceState()之后的任何转换都可能会丢失系统会回收资源的活动,并在以后重新创建。

评论


嘿,芬克,我在这里有一个问题,如果该活动或片段已停止,那么如何在该活动或片段上调用onBackPressed。上面的异常似乎是由某个UI事件产生的(即按BACK键),但是我无法找出Async Task和Back键之间的关系。

– dcool
2011年11月9日在3:08



由于您可以将片段过渡保存到后退状态,因此按“后退”按钮可能会导致您保存的过渡相反(因此旧片段又回来了)。在销毁您的活动以将资源还原到系统之前(并非总是在onStop之后),将调用onSaveInstanceState。抱歉,我的回答不太清楚。

– FunkTheMonk
2011年11月9日9:38

放克,但我在应用程序中未使用任何片段。它可能是本机代码中使用的片段。早些时候我以为你在说同样的话。

– dcool
2011年11月9日10:33

我有一个AsyncTask与片段的引用。从onSaveInstanceState删除super()调用并将我的AsyncTask中的引用替换为WeakReference 后,问题解决了。

–布法罗
2012年6月28日15:31

@Buffalo绝对不是解决问题的方法。您应该始终调用super.onSaveInstanceState()。

– Alex Lockwood
13年8月16日在15:27

#4 楼

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

评论


调用onPostResume()可确保调用onResumeFragments(),对我而言,这是理想的解决方案。

– j2emanue
14年6月13日在16:19

#5 楼

在屏幕被锁定\空白并且保存了Activity +对话框的实例状态之后,在对话框片段上调用dismiss()时,也会发生这种情况。要解决此呼叫:

dismissAllowingStateLoss()


从字面上看,每次我关闭对话框时,我都不再关心它的状态了,所以可以这样做-您实际上并没有丢失任何状态。

评论


这是我的确切问题!先生,您真聪明!

– Tash Pemhiwa
16年11月9日14:06

#6 楼

简短且有效的解决方案:

遵循简单的步骤:

步骤1:覆盖各个片段中的onSaveInstanceState状态。并从其中删除超级方法。

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


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

fragmentTransaction.commitAllowingStateLoss();


评论


删除超级方法就可以了,您能解释为什么吗?删除它安全吗?

–布鲁斯
16年6月6日在16:49

删除super()是不安全的,此后您将丢失其他数据conf!

–死鱼
16-2-28在20:27



#7 楼

我认为生命周期状态可以帮助防止此类崩溃(从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()

#8 楼

这对我有用...我自己发现了...希望对您有所帮助!

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();
    }
}


#9 楼

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


我的Activity已暂停和停止,这意味着onSaveInstanceState()被
如果发生任何结果,我都会进行交易以显示/隐藏片段,这会导致此IllegalStateException。

我所做的是next:


为确定是否要执行的操作(例如,从camere拍照-isPhotoTaken)而添加的值-可以是布尔值或整数值,具体取决于您需要多少不同的交易。 br />在重写的onResumeFragments()方法中,我检查了我的值,并在进行了片段事务之后需要。在这种情况下,在onSaveInstanceState之后不会执行commit(),因为状态是通过onResumeFragments()方法返回的。


#10 楼

我通过onconfigurationchanged解决了这个问题。诀窍是根据android活动的生命周期,当您显式调用intent(相机intent或任何其他一个)时;活动被暂停,在这种情况下将调用onsavedInstance。将设备旋转到活动进行期间以外的其他位置时;进行片段提交等片段操作会导致非法状态异常。对此有很多抱怨。这与android活动生命周期管理和正确的方法调用有关。
要解决此问题,我做到了:
1-重写活动的onsavedInstance方法,并确定当前的屏幕方向(纵向或横向),然后进行设置您的活动暂停前屏幕的方向。这样,如果您的活动已被另一个活动所旋转,则您可以锁定该屏幕的旋转。
2-然后,覆盖活动的onresume方法,并将方向模式现在设置为传感器,以便在保存方法之后调用它会在配置上花费更多时间来正确处理旋转。

您可以将此代码复制/粘贴到您的活动中以进行处理:

@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);
} 


#11 楼

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

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

我用

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

将它包围起来,然后做到了。好的,我没有显示对话框,但是在这种情况下很好。

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

有趣的是,用户从未离开过该应用程序。相反,杀手was是出现的AdMob插页式广告。

评论


同样在这里。我解决了覆盖'show(FragmentManager manager,String tag)'方法,用'commitAllowingStateLoss'替换'commit';丢失了一些东西,因为我无法设置对话框的两个私有属性:mDismissed和mShownByMe。但这似乎每次都起作用:)

– Francesco Ditrani
2015年4月28日在20:58



我为DialogFragment提供了一种替代解决方案,可以避免出现此异常:github.com/AndroidDeveloperLB/DialogShard

– Android开发人员
16-10-25在8:10

#12 楼

我针对该问题的解决方案是

在片段添加方法中:

@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();
}


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

评论


Trues ..捕获异常可以避免应用程序崩溃,但是出现行为问题,例如碎片留在屏幕上或未添加。

– Marcos Vasconcelos
13年8月6日在19:14

继续向下滑。真相就在那里

–茴香
15年8月12日在12:21

#13 楼

我遇到了这个问题。但是我认为这个问题与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之后为true。

此问题很少发生。我从未遇到过此问题。我无法再次发生该问题。

我已发现问题25517

它可能是在以下情况下发生的


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

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

@Override
public void onBackPressed() {

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


评论


我并没有真正解决问题,但是这个问题与commit和commitAllowStateLoss无关。

–oO_ox
16年8月17日在7:19

#14 楼

我的应用程序中遇到了同样的问题。我已经解决了这个问题,只需在上一类中调用super.onBackPressed();并在当前类中使用该片段调用commitAllowingStateLoss()

评论


谢谢。此解决方案使用commitAllowingStateLoss()而不是commit()解决了问题

– Chintak Patel
17年8月21日在6:51

避免使用commitAllowingStateLoss()medium.com/@elye.project/…

– swooby
18-10-5在22:23

#15 楼

如果用户旋转屏幕,以便可以加载与新方向相关联的资源,则会调用onSaveInstance。

该用户旋转屏幕,然后按下“后退”按钮是有可能的(因为也有可能该用户在使用您的应用程序时弄翻了手机)

评论


尽管配置更改(例如方向更改)可能导致此异常,但这不是根本原因。

– Alex Lockwood
2013年9月15日下午2:56

#16 楼

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

文章。
fragment.isResumed()检查可以使用onSaveInstanceState方法帮助我进行onDestroyView w / o。

#17 楼

我遇到了同样的问题,并且在对所有文章,博客和stackoverflow进行了长达一天的分析之后,我找到了一个简单的解决方案。根本不要使用saveInstanceState,这是只有一行代码的条件。在片段代码上:

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


#18 楼

每当您尝试加载片段但活动将其状态更改为onPause()时都会发生这种情况,例如,当您尝试获取数据并将其加载到活动中但用户单击某些按钮并具有移动到下一个活动。

您可以通过两种方式解决此问题

您可以使用transaction.commitAllowingStateLoss()而不是transaction.commit()来加载片段,但是可能会结束



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

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

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


然后在加载片段时检查活动是否存在并仅在活动为前景时加载。 >
if(mIsResumed){
 //load the fragment
}


#19 楼

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

根据doc:因此,请使用commitNow替换:

 * If you are committing a single transaction that does not modify the
 * fragment back stack, strongly consider using
 * {@link FragmentTransaction#commitNow()} instead. This can help avoid
 * unwanted side effects when other code in your app has pending committed
 * transactions that expect different timing.
 *
 * @return Returns true if there were any pending transactions to be
 * executed.
 */
public abstract boolean executePendingTransactions();


#20 楼

好吧,在尝试了所有上述解决方案后都没有成功(因为基本上我没有事务)。 ,错误会增加。 ):

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();
}


#21 楼

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

当我更改为使用startactivityforresult时,该异常消失了:)

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

#22 楼

我在按返回按钮取消地图片段活动上的意图选择器时遇到了此异常。
我通过将onResume()(我正在初始化片段并提交事务的代码)替换为onStart( ),该应用现在可以正常运行了。
希望对您有所帮助。

#23 楼

此问题已在Android 4.2和支持库的源代码中修复。[*]

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

如果您使用的是支持库,则不必担心此错误(长时间) [*]。但是,如果您直接使用API​​(即不使用支持库的FragmentManager)并在Android 4.2以下定位API,则需要尝试一种解决方法。

[*]在撰写本文时,Android SDK Manager仍在分发存在此错误的旧版本。

编辑我将在此处添加一些说明,因为无论如何,对此我显然感到困惑答案。

有几种不同(但相关)的情况可能导致引发此异常。我在上面的回答是指问题中讨论的特定实例,即Android中的错误,该错误随后已修复。如果由于其他原因而导致此异常,那是因为您在不应该添加(或删除片段状态后)的情况下添加/删除了片段。如果您处于这种情况,则可能对您有用“嵌套片段-IllegalStateException“在onSaveInstanceState之后无法执行此操作”。

#24 楼

经过研究后,此问题的解决方案是在onresume中进行片段提交。

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

#25 楼

我的用例:我在片段中使用了侦听器,以通知活动发生了一些事情。我对回调方法进行了新的片段提交。第一次使用时效果很好。但是在方向更改时,将使用保存的实例状态重新创建活动。在那种情况下,片段不再被创建意味着该片段具有监听器,该监听器是旧的破坏活动。回调方法将以任何方式触发。它去导致问题的被破坏的活动。解决方案是使用当前实时活动在片段中重置侦听器。这样就解决了问题。

#26 楼

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

#27 楼

就我而言,出现相同的错误例外,我将“ onBackPressed()”放在一个可运行的程序中(您可以使用任何视图):

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

不明白为什么,但是它有效!

评论


只有在正确布局视图并将其绘制到屏幕后,才能在视图上进行发布。这通常意味着活动本身已完全恢复,因此没有问题

– Mercato
17年4月4日在16:18

#28 楼

您可能正在调用fragmentManager.popBackStackImmediate();活动暂停时。活动尚未完成,但已暂停且不在前台。您需要在popBackStackImmediate()之前检查活动是否已暂停。

#29 楼

我注意到一些非常有趣的事情。我的应用程序中有打开手机图库的选项,并且设备询问要使用哪个应用程序,在那里我单击对话框旁边的灰色区域并看到了此问题。我注意到我的活动是如何从onPause,onSaveInstanceState回到onResume的,访问onCreateView并不是偶然的。我正在onResume上进行交易。因此,我最终要做的是设置一个标记,使其在onPause处被否定,但在onCreateView处为真。如果该标志为true,则onResume,然后执行onCommit,否则commitAllowingStateLoss。我可以继续浪费很多时间,但我想检查生命周期。我有一台sdkversion 23的设备,但没有出现此问题,但我有一台21的设备,在那里我看到了它。

#30 楼

您可以在popBackStackImmediate之前使用FragmentActivity.onStart

,例如:

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/ legalstateexception-can-not-perform.html