为什么在屏幕旋转时 Fragment 不会保持状态? [英] Why won't Fragment retain state when screen is rotated?

查看:32
本文介绍了为什么在屏幕旋转时 Fragment 不会保持状态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在让 PreferenceFragment 中的一些自定义 DialogPreference 子类在屏幕旋转时保持可见时遇到了一些麻烦.我在使用 PreferenceActivity 时没有遇到这个问题,所以我不知道是 Android 错误还是我的代码有问题,但我希望有人确认他们是否有相同的体验.

I've been having some trouble getting some custom DialogPreference subclasses inside a PreferenceFragment to remain visible when the screen is rotated. I don't experience this problem when using a PreferenceActivity, so I don't know whether it's an Android bug or a problem with my code, but I'd like someone to confirm whether they are having the same experience.

为了测试这一点,首先创建一个包含至少一个 DialogPreference 的首选项屏幕(哪个子类无关紧要).然后将其显示在 PreferenceActivity 中.运行应用程序时,按下 DialogPreference 以显示对话框.然后旋转屏幕使方向改变.对话框是否保持可见?

To test this, first create a preference screen containing at least one DialogPreference (it doesn't matter which subclass). Then display it in a PreferenceActivity. When you run your app, press on the DialogPreference so that it's dialog shows. Then rotate the screen so the orientation changes. Does the dialog remain visible?

然后尝试相同的方法,但使用 PreferenceFragment 来显示您的首选项而不是 PreferenceActivity.同样,当您旋转屏幕时,对话框是否仍然可见?

Then try the same, but with a PreferenceFragment to display your preferences instead of a PreferenceActivity. Again, does the dialog remain visible when you rotate the screen?

到目前为止,我发现如果使用 PreferenceActivity 对话框将保持可见,但如果使用 PreferenceFragment 则不可见.查看DialogPreference的源代码,似乎正确的行为是让对话框保持可见,因为 isDialogShowing 是在屏幕重新定向时调用 onSaveInstanceState() 时保存的状态信息.因此,我认为一个错误可能会阻止 PreferenceFragment(以及其中的所有内容)恢复该状态信息.

So far, I've found that the dialog will remain visible if using a PreferenceActivity, but not if using a PreferenceFragment. Looking at the source code for DialogPreference, it seems that the correct behaviour is for the dialog to remain visible, because isDialogShowing is the state information that gets saved when onSaveInstanceState() is called on screen re-orientation. Therefore, I think a bug may be preventing the PreferenceFragment (and everything inside it) from restoring that state information.

如果是 Android 的 bug,那么它的影响是深远的,因为任何使用 PreferenceFragment 的人都无法保存和恢复状态信息.

If it is an Android bug, then it has far-reaching implications, because anyone using PreferenceFragment cannot save and restore state information.

有人可以确认吗?如果这不是错误,那是怎么回事?

Can someone please confirm? If it's not a bug, then what is going on?

推荐答案

终于想出了解决这个问题的办法.事实证明,这不是错误,而是 Android 开发人员文档中的问题/疏忽.

Finally figured out a solution to this problem. Turns out it's not a bug, but a problem/oversight in the Android developer documentation.

你看,我正在关注 PreferenceFragment 教程这里.那篇文章告诉您执行以下操作以在 Activity 中实例化您的 PreferenceFragment:

You see, I was following the PreferenceFragment tutorial here. That article tells you to do the following in order to instantiate your PreferenceFragment within an Activity:

public class SettingsActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Display the fragment as the main content.
        getFragmentManager().beginTransaction()
                .replace(android.R.id.content, new SettingsFragment())
                .commit();
    }
} 

这样做的问题是,当您更改屏幕方向(或任何其他破坏和重新创建 Activity 的操作)时,您的 PreferenceFragment 将被创建两次,这就是导致它失去它的状态.

The problem with this is that when you change the screen orientation (or any other action that destroys and re-creates the Activity), your PreferenceFragment will get created twice, which is what causes it to lose its state.

第一次创建将通过 Activity 调用 super.onCreate()(如上所示)进行,后者将调用 onActivityCreated() 您的 PreferenceFragment () 方法和它包含的每个 Preference 的 onRestoreInstanceState() 方法.这些将成功恢复一切的状态.

The first creation will occur via the Activity's call to super.onCreate() (shown above), which will call the onActivityCreated() method for your PreferenceFragment () and the onRestoreInstanceState() method for each Preference it contains. These will successfully restore the state of everything.

但是一旦对 super.onCreate() 的调用返回,您可以看到 onCreate() 方法将继续创建 PreferenceFragment 一个 第二次时间.因为它再次被毫无意义地创建(这一次,没有状态信息!),所有刚刚成功恢复的状态将被完全丢弃/丢失.这解释了为什么在 Activity 被销毁时可能显示的 DialogPreference 在重新创建 Activity 后将不再可见.

But then once that call to super.onCreate() returns, you can see that the onCreate() method will then go on to create the PreferenceFragment a second time. Because it is pointlessly created again (and this time, without state information!), all of the state that was just successfully restored will be completely discarded/lost. This explains why a DialogPreference that may be showing at the time that the Activity is destroyed will no longer be visible once the Activity is re-created.

那么有什么解决办法呢?好吧,只需添加一个小检查来确定 PreferenceFragment 是否已经创建,如下所示:

So what's the solution? Well, just add a small check to determine whether the PreferenceFragment has already been created, like so:

public class SettingsActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Fragment existingFragment = getFragmentManager().findFragmentById(android.R.id.content);
        if (existingFragment == null || !existingFragment.getClass().equals(SettingsFragment.class))
        {
            // Display the fragment as the main content.
            getFragmentManager().beginTransaction()
                .replace(android.R.id.content, new SettingsFragment())
                .commit();
        }
    }
}

或者另一种方法是简单地检查 onCreate() 是否意味着恢复状态,如下所示:

Or another way is to simply check if onCreate() is meant to restore state or not, like so:

public class SettingsActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (savedInstanceState == null)
        {
            // Display the fragment as the main content.
            getFragmentManager().beginTransaction()
                .replace(android.R.id.content, new SettingsFragment())
                .commit();
        }
    }
}

所以我想这里学到的教训是 onCreate() 有双重作用——它可以第一次设置一个 Activity,或者它可以从早期的状态恢复.

So I guess the lesson learnt here is that onCreate() has a dual role - it can set up an Activity for the first time, or it can restore from an earlier state.

答案这里让我意识到了这个解决方案.

The answer here led me to realizing this solution.

这篇关于为什么在屏幕旋转时 Fragment 不会保持状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆