popBackStack and commitAllowingStateLoss

12

我在Activity的onCreate()方法中调用popBackStack(),但是我遇到了异常:

Caused by java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

android.app.FragmentManagerImpl.checkStateLoss (FragmentManager.java:1428)
android.app.FragmentManagerImpl.enqueueAction (FragmentManager.java:1446)
android.app.FragmentManagerImpl.popBackStack (FragmentManager.java:572)

我了解解决此异常的一种方法,前提是您对UI和最终用户的影响感到满意,那就是调用commitAllowingStateLoss。

问题是,在popBackStack中没有提交调用。是否有其他方法可以调用popBackStack并允许状态丢失?

我应该说,我正在onPostResume中执行此操作,并获得此异常。


我认为当您在非活动状态下调用popBackStack()时,会出现此错误。请发布您的代码以进行进一步调试。 - arjun
@arjun 我在onPostResume中调用popBackStack,根据我找到的所有参考资料,这是在应用程序恢复后调用它的安全位置。我无法发布更多代码,因为应用程序非常庞大,但归结起来就是在onPostResume中调用了popBackStack。肯定有一些地方可以在应用程序安全恢复后重新初始化GUI吧? - user3690202
正如@arjun所建议的,你尝试在onResumeFragments()中执行它了吗? - azizbekian
在添加/删除片段之前,先尝试应用!isFinishing()。 - silentsudo
@azizbekian Activity没有onResumeFragments方法。FragmentActivity有,但我没有使用它。 - user3690202
4个回答

1
经过大量研究,我得出结论:在Activity恢复时,不可能操纵Android上的片段。按照提到的博客文章,我尝试了onPostResume()和onResumeFragments()来从后退栈中弹出片段,但两者在发布到生产环境时都会导致间歇性崩溃。
这个现实的缺点是,如果您想要例如显示一个关卡结束的片段,然后是插页广告,接着是下一关(作为与结束关卡片段不同的片段),那么就无法使用片段。
对于我的个人情况,我从我的应用程序中删除了所有片段。我继续使用布局,因为在XML中编辑UI很有用,但是当前状态下Fragment生命周期无法使用,因此我自己编写了“片段”子系统,但更好,因为它可以从Activities onResume进行操作。
我希望有一天Google会修复这个问题,因为它使得为Android开发变得非常不愉快。无论如何,如果有人需要使用片段但不喜欢通常会遇到的onSaveInstanceState异常,这里是我的“GameScreen”实现(类似于片段,但更好)。
/**
 * GameScreen
 */
public class GameScreen {

    private int id;
    private View view;
    private ViewGroup viewGroup;
    protected MainActivity mainActivity;

    public GameScreen(MainActivity mainActivity, int id) {
        this.mainActivity = mainActivity;
        this.id = id;
    }

    public void create(LayoutInflater layoutInflater, ViewGroup viewGroup) {
        this.viewGroup = viewGroup;
        view = layoutInflater.inflate(id, viewGroup, false);
        viewGroup.addView(view);
    }

    public void show() {
        for (int i = 0; i < viewGroup.getChildCount(); i++) {
            View v = viewGroup.getChildAt(i);
            if (v != view) {
                v.setVisibility(View.INVISIBLE);
            }
        }

        view.setVisibility(View.VISIBLE);
    }
}

0

我没有使用FragmentActivity,只是Activity。那篇博客文章(我以前看过)已经“保证”从onPostResume()中执行这个操作会起作用 - 但很明显它并没有。因此,那篇博客包含的信息是根本错误的。 - user3690202
但建议使用扩展FragamentActivityAppCombatActivity,在其中可以尝试使用onResumeFragments()回调函数。 - arjun
你能引用推荐的精确位置吗?当你在Android Studio中创建一个新的片段活动项目时,它肯定不是默认的基类。 - user3690202
1
使用AppCompat可以使Android版本之间的生命周期更加一致;迁移所有代码并不是一个坏主意。 - rds
2
@rds - 在同一句话中使用Android、Lifecycle和Consistent这几个词应该是犯罪行为 :-) - user3690202
显示剩余5条评论

0

0
这是一个简单的解决方案,帮助我找到了解决办法。
正如一些博客文章中提到的,一切都取决于你的应用程序是否在前台,或者当应用程序进入后台时,捆绑保存是否正确进行。人们会陷入困境,因为他们可能使用了navGraph或popBackStack(),而不是FragmentTransition,而在这种情况下,很难添加commit()或将其更改为commitAllowingStateLoss()。
试试这个。
Handler(Looper.getMainLooper()).post {
requireActivity().supportFragmentManager.popBackStack("FragmentName")
}

使用此处理程序和Looper,它会在应用程序进入前台时执行修复操作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接