出现异常“IllegalStateException:onSaveInstanceState 后无法执行此操作”
Posted
技术标签:
【中文标题】出现异常“IllegalStateException:onSaveInstanceState 后无法执行此操作”【英文标题】:getting exception "IllegalStateException: Can not perform this action after onSaveInstanceState" 【发布时间】:2011-11-20 02:38:46 【问题描述】:我有一个 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)
【问题讨论】:
您找到解决方案了吗?这里有同样的问题:***.com/questions/7575921/… 我遇到了同样的问题and found a simple solution that works for me @phlebas 不,你没有。您的问题涉及对话,而这不是。堆栈跟踪匹配的第一行是不够的。其余的则非常不同。我这样说是因为我刚刚查看了您的问题,不幸的是,这对我没有帮助。 你在那个活动中使用线程还是 AsynTask? 我在blog post 中讨论了这个错误...你应该阅读它。 :) 【参考方案1】:这是迄今为止我遇到的最愚蠢的错误。我有一个 Fragment
应用程序在 API 和 Force Closing
上完美运行 API > 11 .
在对saveInstance
的调用中,我真的无法弄清楚它们在Activity
生命周期内发生了什么变化,但我是这样解决这个问题的:
@Override
protected void onSaveInstanceState(Bundle outState)
//No call for super(). Bug on API Level > 11.
我只是不打电话给.super()
,一切都很好。我希望这可以为您节省一些时间。
编辑: 经过更多研究,这是支持包中已知的bug。
如果您需要保存实例,并向您的 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: 据我所知,上述解决方案正在修复早期 support.v4 库中的问题。但如果您对此仍有疑问,您必须还阅读@AlexLockwood 的博客:Fragment Transactions & Activity State Loss
博文摘要(但我强烈建议您阅读):
从不commit()
在蜂窝前的 onPause()
和蜂窝后的 onStop()
之后进行交易
在Activity
生命周期方法中提交事务时要小心。 使用 onCreate()
、onResumeFragments()
和 onPostResume()
避免在异步回调方法中执行事务
仅在不得已的情况下使用commitAllowingStateLoss()
【讨论】:
你应该使用 commitAllowingStateLoss() 而不是 commit() 因此在 onSaveInstanceState 中不调用 super 将阻止 FragmentManager 保存所有 Fragment 的状态并恢复它们。这可能会导致旋转问题。另外,我刚刚尝试了将垃圾放入捆绑包中的另一件事,这对我来说没有任何区别。不确定它会如何 - 您在支持包中引用的错误是 NullPointerException,并且看起来不像 IllegalStateException... @mehcommitAllowingStateLoss()
只是避免了异常。它不能保护您的应用程序免受意外状态丢失。看到这个blog post。
@AlexLockwood 所以从那篇博客文章中我们可以了解到我们应该在片段内进行所有的网络调用(如果需要,显示一些临时进度 ui),这是我们可以避免获取的唯一方法可能发生此异常,因为在某些异步方法调用之后调用了提交。
我没有得到第一点:"NEVER commit() transactions after ... onStop() on post-Honeycomb" 。如果我需要一个按钮来触发一个片段被另一个片段替换怎么办?我是否应该放置一个布尔值来检查活动是否已在 onStop 完成,如果完成,则改为调用 commitAllowingStateLoss?另外,如果我在片段中有一个片段,我需要在单击按钮时进行替换?【参考方案2】:
查看 Android 源代码以了解导致此问题的原因会发现 FragmentManagerImpl
类(Activity 中可用的实例)中的标志 mStateSaved 的值为 true。当来自Activity#onSaveInstanceState
的调用保存返回堆栈 (saveAllState) 时,它设置为 true。
之后,来自 ActivityThread 的调用不会使用来自 FragmentManagerImpl#noteStateNotSaved()
和 dispatch()
的可用重置方法重置此标志。
在我看来,有一些可用的修复程序,具体取决于您的应用正在做什么和使用什么:
好方法
首先:我会宣传Alex Lockwood article。然后,从我目前所做的:
对于不需要保留任何状态信息的片段和活动,请致电commitAllowStateLoss。取自文档:
允许在保存活动状态后执行提交。这是危险的,因为如果活动需要稍后从其状态恢复,提交可能会丢失,因此这应该只用于 UI 状态可以在用户上意外更改的情况。如果片段显示只读信息,我想这是可以使用的。或者即使它们确实显示了可编辑的信息,也可以使用回调方法来保留已编辑的信息。
在事务提交后(您刚刚调用了commit()
),调用FragmentManager.executePendingTransactions()
。
不推荐的方式:
正如上面提到的Ovidiu Latcu,不要打电话给super.onSaveInstanceState()
。但这意味着您将丢失整个活动状态以及片段状态。
覆盖onBackPressed
并在其中仅调用finish()
。如果您的应用程序不使用 Fragments API,这应该没问题;如在super.onBackPressed
中,有一个对FragmentManager#popBackStackImmediate()
的调用。
如果您同时使用 Fragments API 并且您的活动状态很重要/至关重要,那么您可以尝试使用反射 API FragmentManagerImpl#noteStateNotSaved()
进行调用。但这是一种 hack,或者可以说这是一种解决方法。我不喜欢它,但就我而言,这是完全可以接受的,因为我有一个来自旧版应用程序的代码,它使用了已弃用的代码(TabActivity
和隐含的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);
干杯!
【讨论】:
这似乎也发生在 ActionBarSherlock 上,在 Gingerbread 下,所以检查 Build Id 的情况似乎没有意义...... :( 另外,你应该指出 - 这也不适合 ABS 使用:) @t0mm13b:上面的代码代表我的项目,因为它既不使用片段,也不支持.FragmentActivity。它在 android.app.Activity 上运行,并且由于触发异常的不一致是由 FragmentManager (API 级别 11 以上)引起的,这就是为什么要检查......如果你相信邪恶的根源对你来说也是一样的,请随意删除检查。 ABS 是另一回事,因为它运行在兼容性包和 support 的实现之上。FragmentActivity 可能使用 FragmentManager 的相同实现,瞧:同样的问题。 @t0mm13b:要添加更多字符,因为 600 个字符还不够,您必须首先调查是什么真正导致了这种情况。您还必须意识到,上面是一个丑陋的黑客,如果它运行与否,我不承担任何责任(对我来说,考虑到这种情况,这是最好的解决方案)。如果您必须使用它,请仔细检查兼容源代码中的变量命名,因为它们可能与标准包不同。我希望下一个版本的兼容性包能解决这个问题,但从 Android 的经验来看,发生这种情况的机会很少...... Uhhh... 它与bug report which 中的问题完全相同,这是此 OP 问题的重点。我坚持我的意见 - 你应该明确提出免责声明并说它不能保证并且应该声明你没有使用片段 - 否则为什么还要发帖那个答案要么! :) 只是说...【参考方案3】:如果您在调用片段活动的onSaveInstanceState()
后尝试执行片段转换,则会发生此类异常。
发生这种情况的一个原因是,如果您在活动停止时让AsyncTask
(或Thread
)继续运行。
如果系统回收活动以获取资源并稍后重新创建,则调用 onSaveInstanceState()
之后的任何转换都可能会丢失。
【讨论】:
Hey Funk,我有一个问题,如果该活动或片段已停止,怎么会在该活动或片段上调用 onBackPressed。上述异常似乎是由某些 UI 事件(即按下 BACK 键)产生的,但我无法找出 Async Task 和 Back 键之间的关系。 由于您可以将片段转换保存到后退状态,因此按下后退按钮可能会导致您保存的转换反转(因此旧片段会返回)。 onSaveInstanceState 在您的活动被销毁以将资源恢复到系统之前调用,并非总是在调用 onStop 之后调用。抱歉,我的回答不是很清楚。 Funk,但我没有在我的应用程序中使用任何片段。它可能是本机代码中使用的片段。早些时候我以为你在说同样的事情。 我有一个 AsyncTask 引用了一个片段。从 onSaveInstanceState 中删除 super() 调用并将我的 AsyncTask 中的引用替换为 WeakReferencesuper.onSaveInstanceState()
。【参考方案4】:
在显示您的片段之前调用 super.onPostResume() 或在调用 super.onPostResume() 之后将代码移动到 onPostResume() 方法中。这样就解决问题了!
【讨论】:
调用 onPostResume() 确保 onResumeFragments() 被调用,对我来说这是理想的解决方案。【参考方案5】:在屏幕已锁定\空白且 Activity + 对话框的实例状态已保存后,在对话框片段上调用 dismiss()
时也会发生这种情况。要绕过这个电话:
dismissAllowingStateLoss()
从字面上看,每次我关闭一个对话框时,我都不再关心它的状态,所以这是可以的 - 你实际上并没有失去任何状态。
【讨论】:
这正是我的问题!楼主你太棒了!【参考方案6】:短而有效的解决方案:
按照简单的步骤:
第 1 步:覆盖相应片段中的 onSaveInstanceState 状态。并从中删除超级方法。
@Override
public void onSaveInstanceState(Bundle outState)
;
第 2 步:使用 CommitAllowingStateLoss();而不是提交(); while 片段操作。
fragmentTransaction.commitAllowingStateLoss();
【讨论】:
删除超级方法成功了,你能解释一下为什么吗?删除它是否安全? 删除super()是不安全的,之后你会丢失其他数据!【参考方案7】:我认为生命周期状态可以帮助防止从 Android 支持 lib 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。
接下来是我做的:
-
附加值用于确定我想要的操作是否已完成(例如,从相机拍照 - isPhotoTaken) - 它可以是布尔值或整数值,具体取决于您需要多少不同的交易。
在重写的 onResumeFragments() 方法中,我检查了我的值,并在进行了我需要的片段事务之后。在这种情况下,在 onSaveInstanceState 之后没有完成 commit(),因为在 onResumeFragments() 方法中返回了状态。
【讨论】:
【参考方案10】:我通过 onconfigurationchanged 解决了这个问题。诀窍是,根据 android 活动生命周期,当您显式调用意图(相机意图或任何其他意图)时;在这种情况下,活动被暂停并调用 onsavedInstance。将设备旋转到活动活动期间以外的其他位置时;进行片段提交等片段操作会导致非法状态异常。有很多抱怨。这是关于 android 活动生命周期管理和适当的方法调用的东西。 为了解决它,我这样做了: 1-覆盖您的活动的 onsavedInstance 方法,并确定当前的屏幕方向(纵向或横向),然后在您的活动暂停之前将您的屏幕方向设置为它。这样,您就可以锁定活动的屏幕旋转,以防它被另一个活动旋转。 2-然后,覆盖活动的onresume方法,并将您的方向模式现在设置为传感器,以便在调用onsaved方法后它会再调用一次onconfiguration以正确处理旋转。
您可以将此代码复制/粘贴到您的活动中以进行处理:
@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 ***, 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()”时没有找到它。
有趣的是,用户永远不会离开应用程序。相反,杀手是出现的 AdMob 插页式广告。
【讨论】:
这里也一样。我已经解决了覆盖'show(FragmentManager manager,String tag)'方法,用'commitAllowingStateLoss'替换'commit';因为我无法设置对话框的两个私有属性而丢失了一些东西:mDismissed 和 mShownByMe。但它似乎每次都有效:) 我已经为 DialogFragment 提供了一个替代解决方案,可以避免这个异常:github.com/AndroidDeveloperLB/DialogShard【参考方案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.. 捕获异常可能会避免应用程序崩溃,但会出现诸如碎片留在屏幕上或未添加的行为问题。 继续滚动。真相就在那里【参考方案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 之后为真。
这个问题很少发生。我从来没有遇到过这个问题。我不能再次出现这个问题。
我找到issue 25517
可能发生在以下情况
在 onSaveInstanceState 之后,新活动开始之前调用返回键。
use onStop() in code
我不确定问题的根源是什么。 所以我用了一种丑陋的方式。
@Override
public void onBackPressed()
try
super.onBackPressed();
catch (IllegalStateException e)
// can output some information here
finish();
【讨论】:
我并没有真正解决问题,但是这个问题与commit和commitAllowStateLoss无关。【参考方案14】:我在我的应用程序中遇到了同样的问题。我已经解决了这个问题,只需在上一课上调用super.onBackPressed();
并在当前课上使用该片段调用commitAllowingStateLoss()
。
【讨论】:
谢谢。此解决方案解决了问题 uisngcommitAllowingStateLoss()
而不是 commit()
避免使用 commitAllowingStateLoss() medium.com/@elye.project/…【参考方案15】:
如果用户旋转屏幕以加载与新方向相关的资源,则会调用 onSaveInstance。
这个用户有可能旋转了屏幕然后按下了返回按钮(因为这个用户也有可能在使用你的应用程序时摸索了他们的手机)
【讨论】:
虽然配置更改(例如方向更改)可能导致此异常,但它们不是根本原因。【参考方案16】:阅读 http://chris-alexander.co.uk/on-engineering/dev/android-fragments-within-fragments/
文章。 fragment.isResumed() 检查有助于我在 onDestroyView 中使用 onSaveInstanceState 方法。
【讨论】:
【参考方案17】:我遇到了同样的问题,在对所有文章、博客和 *** 进行了一天的分析后,我找到了一个简单的解决方案。根本不要使用 savedInstanceState ,这是一行代码的条件。关于片段代码:
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(null);
.....
【讨论】:
【参考方案18】:当您尝试加载片段但活动已将其状态更改为 onPause() 时,就会发生这种情况。例如,当您尝试获取数据并将其加载到活动时,当用户单击一些时,就会发生这种情况按钮并已移至下一个活动。
你可以通过两种方式解决这个问题
您可以使用 transaction.commitAllowingStateLoss() 而不是 transaction.commit() 来加载片段,但最终可能会丢失已完成的提交操作。
或
确保 Activity 在加载片段时处于恢复状态并且不会暂停。 创建一个布尔值并检查活动是否不会进入 onPause() 状态。
@Override
public void onResume()
super.onResume();
mIsResumed = true;
@Override
public void onPause()
mIsResumed = false;
super.onPause();
然后在加载片段时检查是否存在活动并仅在活动处于前台时加载。
if(mIsResumed)
//load the fragment
【讨论】:
【参考方案19】:解决问题的另一种生命周期方法是使用最新发布的生命周期-ktx 和 kotlin。
lifecycleScope.launchWhenResumed
// your code with fragment or dialogfragment
闭包会在恢复状态后运行,所以即使是这个方法也会在之后调用 停止,下次恢复时会安全执行。
你也可以选择喜欢
lifecycleScope.launchWhenCreated
// or
lifecycleScope.launchWhenStarted
适合你的情况。
destroy到来时代码将被取消。
Google 文档链接: https://developer.android.com/kotlin/ktx#lifecycle
【讨论】:
【参考方案20】:感谢@gunar,但我认为有更好的方法。
根据文档:
* 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();
所以用commitNow
代替:
fragmentTransaction.commit();
FragmentManager.executePendingTransactions()
【讨论】:
【参考方案21】:好吧,在尝试了上述所有解决方案后都没有成功(因为基本上我没有交易)。
在我的情况下,我使用 AlertDialogs 和 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();
【讨论】:
【参考方案22】:当我在一个片段中使用 startactivity 时,我会得到这个异常;
当我改为使用 startactivityforresult 时,异常消失了 :)
所以修复它的简单方法是使用 startActivityForResult api :)
【讨论】:
【参考方案23】:当我按下返回按钮取消地图片段活动的意图选择器时,我遇到了这个异常。 我通过将 onResume()(我在其中初始化片段并提交事务)的代码替换为 onStart() 解决了这个问题,并且应用程序现在运行良好。 希望对您有所帮助。
【讨论】:
【参考方案24】:这已在 Android 4.2 和支持库的源代码中修复。[*]
有关原因(和解决方法)的详细信息,请参阅 Google 错误报告: http://code.google.com/p/android/issues/detail?id=19917
如果您正在使用支持库,那么您不必担心这个错误(长期)[*]。但是,如果您直接使用 API(即不使用支持库的 FragmentManager)并针对低于 Android 4.2 的 API,则需要尝试其中一种解决方法。
[*] 在撰写本文时,Android SDK Manager 仍在分发存在此错误的旧版本。
编辑我将在此处添加一些说明,因为我显然以某种方式混淆了对这个答案投反对票的人。
有几种不同(但相关)的情况会导致引发此异常。我上面的回答是指问题中讨论的特定实例,即 Android 中的一个错误,该错误随后已被修复。如果您因为另一个原因而收到此异常,那是因为您在不应该添加/删除片段时(在保存片段状态之后)。如果您处于这种情况,那么“Nested Fragments - IllegalStateException “Can not perform this action after onSaveInstanceState””可能对您有用。
【讨论】:
【参考方案25】:经过一番研究,这个问题的解决方案是在 onresume 中进行片段提交。
来源:https://wenchaojames.wordpress.com/2013/01/12/illegalstateexception-from-onactivityresult/
【讨论】:
【参考方案26】:我的用例:我在片段中使用了监听器来通知活动发生了一些事情。我在回调方法上做了新的片段提交。这在第一次时效果很好。但是在方向更改时,活动会使用保存的实例状态重新创建。在这种情况下,不再创建片段意味着片段具有已被销毁的旧活动的侦听器。无论如何,回调方法都会在操作时触发。它会破坏导致问题的活动。解决方案是使用当前实时活动重置片段中的侦听器。这样就解决了问题。
【讨论】:
【参考方案27】:我发现如果另一个应用程序是对话框类型并允许将触摸发送到后台应用程序,那么几乎所有后台应用程序都会因此错误而崩溃。 我认为我们需要在每次执行事务时检查实例是否已保存或恢复。
【讨论】:
【参考方案28】:在我的例子中,有同样的错误异常,我把“onBackPressed()”放在一个可运行文件中(你可以使用你的任何视图):
myView.post(new Runnable()
@Override
public void run()
onBackPressed()
);
我不明白为什么,但它有效!
【讨论】:
在视图上发布只会在视图正确布局并绘制到屏幕后运行 Runnable;这通常意味着 Activity 本身已完全恢复,因此没有问题【参考方案29】:您可能正在调用 fragmentManager.popBackStackImmediate();当活动暂停时。活动未完成但已暂停且不在前台。您需要在 popBackStackImmediate() 之前检查活动是否暂停。
【讨论】:
【参考方案30】:我注意到一些非常有趣的事情。我在我的应用程序中有打开手机图库的选项,并且设备询问要使用什么应用程序,我点击对话框之外的灰色区域并看到了这个问题。我注意到我的活动是如何从 onPause、onSaveInstanceState 回到 onResume 的,它不会碰巧访问 onCreateView。我在 onResume 做交易。所以我最终做的是设置一个标志被否定onPause,但在CreateView上是真的。如果标志为真 onResume 则执行 onCommit,否则执行 commitAllowingStateLoss。我可以继续浪费很多时间,但我想检查生命周期。我有一个 sdkversion 23 的设备,但我没有遇到这个问题,但我有另一个 21 的设备,我看到了。
【讨论】:
以上是关于出现异常“IllegalStateException:onSaveInstanceState 后无法执行此操作”的主要内容,如果未能解决你的问题,请参考以下文章