gpt4 book ai didi

java - 如果重新创建 Activity ,Android显示对话框会导致非法状态异常

转载 作者:行者123 更新时间:2023-11-29 08:34:35 24 4
gpt4 key购买 nike

有三个活动:LoginMainProfile

显然,您可以从Login转到Main。在Button中有一个AppCompatDialogFragment调用Main

    BalanceCalculationDialog dialog = BalanceCalculationDialog.newInstance(model);
dialog.setListener(this);
dialog.show(getSupportFragmentManager(), "TAG");



如果我是用户,则第一次输入 Main对话框。
如果用户转到 Profile,然后显示“后退”对话框。
如果用户退出 Main(带有 finish()Intent#FLAG_ACTIVITY_NEW_TASK标志的 Intent#FLAG_ACTIVITY_CLEAR_TASK)并尝试查看 dialog,则会看到错误。

    java.lang.IllegalStateException: Can not perform this action after 
onSaveInstanceState....CheckStateLoss()...



据我所知,这是因为“ onSaveInstanceState()之后无法提交事务”引起的。

我试图重写此方法,使之成为空的主体,不调用 super,但没有工作。

然后,我找到了解决问题的另一种方法,该方法有效:

@Override
public void show(FragmentManager manager, String tag) {
try {
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commitAllowingStateLoss();
} catch (IllegalStateException e) {
Log.e("ILLEGAL", "Exception", e);
}
}


但是我不明白为什么会这样->捕获 IllegalStateException的数量等于重新创建 Main的数量。例如,我注销20次-那么我将捕获20个提到的异常。因此,我没有找到合适的解决方案。

此外,我还有其他活动可以调用另一个对话框。这些活动也可以用 finish()完成,并且当用户再次打开其中一个时,他没有问题。

对于这种行为以及解决它的正确方法,我将感到非常高兴。非常感谢你。

编辑

出现此问题的原因是使用 RxJava EventBus。当我切换到 Otto Eventbus时,问题消失了。 RxJava允许您发送和获取没有 subscribeunsubscribe的消息,这些消息可能会导致意外的行为。

最佳答案

引发异常是因为您在保存活动状态之后尝试提交FragmentTransaction,从而导致称为Activity状态丢失的现象。但是,在深入了解这实际上意味着什么之前,让我们首先看一下调用onSaveInstanceState()时在幕后发生的情况。 Android应用程序在Android运行时环境中无法控制自己的命运。 Android系统具有随时终止进程以释放内存的能力,并且后台活动可能会被杀死,因此几乎没有警告。为确保有时这种不稳定的行为对用户保持隐藏,框架在使Activity易受破坏之前,通过调用其Activity方法为每个onSaveInstanceState()提供了保存其状态的机会。当以后恢复保存的状态时,将使用户感觉到他们正在前台活动和后台活动之间无缝切换,而不管该活动是否已被系统杀死。

当框架调用onSaveInstanceState()时,它将方法传递给Bundle对象供Activity使用以保存其状态,并且Activity在其中记录其对话框,片段和视图的状态。当方法返回时,系统将Bundle对象通过Binder接口打包到System Server进程,并在其中安全地存储它。当系统稍后决定重新创建Activity时,会将相同的Bundle对象发送回应用程序,以用于恢复活动的旧状态。

那么为什么会引发异常呢?嗯,问题源于以下事实:这些Bundle对象表示Activity被调用时的onSaveInstanceState()快照,仅此而已。这意味着在调用FragmentTransaction#commit()之后再调用onSaveInstanceState()时,该交易将不会被记住,因为该交易从未被记录为活动状态的一部分。从用户的角度来看,事务似乎丢失了,从而导致意外的UI状态丢失。为了保护用户体验,Android不惜一切代价避免了状态丢失,只要发生IllegalStateException便会抛出该错误。

解决此异常的方法是


Activity生命周期方法内提交事务时要小心。绝大多数应用程序只会在第一次调用onCreate()时和/或响应用户输入时才提交事务,因此永远不会遇到任何问题。但是,随着您的交易开始涉足其他Activity生命周期方法,例如onActivityResult()onStart()onResume(),事情会变得有些棘手。例如,您不应该在FragmentActivity#onResume()方法内部提交事务,因为在某些情况下,可以在恢复活动状态之前调用该方法(有关更多信息,请参见文档)。如果您的应用程序需要使用Activity以外的onCreate()生命周期方法提交事务,请使用FragmentActivity#onResumeFragments()Activity#onPostResume()进行。确保在Activity恢复到其原始状态后调用这两种方法,从而避免了状态丢失的可能性。 (作为有关如何完成此操作的示例,请查看我对StackOverflow问题的回答,以获取有关如何响应对Activity#onActivityResult()方法的调用提交FragmentTransactions的一些想法)。
避免在异步回调方法中执行事务。这包括常用的方法,例如AsyncTask#onPostExecute()LoaderManager.LoaderCallbacks#onLoadFinished()。使用这些方法执行事务的问题在于,它们在被调用时不了解Activity生命周期的当前状态。例如,考虑以下事件序列:
一个活动执行一个AsyncTask


用户按下“主页”键,导致活动的
onSaveInstanceState()onStop()方法被调用。
AsyncTask完成并调用onPostExecute()时,不知道
此后活动已停止。 FragmentTransaction已提交
onPostExecute()方法内部,导致引发异常。
通常,在这种情况下避免异常的最佳方法是
只需避免在异步回调方法中提交事务
全部一起。

仅将commitAllowingStateLoss()用作最后的选择。调用commit()commitAllowingStateLoss()的唯一区别是,如果发生状态丢失,后者不会引发异常。通常,您不想使用此方法,因为它暗示着有可能发生状态丢失。当然,更好的解决方案是编写应用程序,以确保在保存活动状态之前调用commit(),因为这将带来更好的用户体验。除非无法避免丢失状态,否则不要使用commitAllowingStateLoss()


但是我必须同意这是Android框架设计的缺陷。 Google开发人员尝试通过多个版本对其进行修复。但是似乎没有解决此问题的好方法。仅了解生命周期,并记得在提交事务之前仔细检查活动状态

关于java - 如果重新创建 Activity ,Android显示对话框会导致非法状态异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45170212/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com