屏幕旋转时,为什么片段不会保留状态?

Xåp*_* - 27 android preferenceactivity android-preferences android-fragments dialog-preference

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

要对此进行测试,首先要创建一个包含至少一个DialogPreference的首选项屏幕(哪个子类无关紧要).然后在PreferenceActivity中显示它.运行应用程序时,请按DialogPreference以显示其对话框.然后旋转屏幕以使方向发生变化.对话框是否仍然可见?

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

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

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

有人可以确认吗?如果它不是一个错误,那么发生了什么?

Xåp*_* - 52

最后找到了解决这个问题的方法.事实证明,这不是一个错误,而是Android开发人员文档中的问题/疏忽.

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

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();
    }
} 
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我想这里学到的经验教训是onCreate()双重角色 - 它可以首次设置一个Activity,也可以从之前的状态恢复.

这里的答案促使我实现了这个解决方案.

  • if(savedInstanceState == null){} 该语句仅在第一次创建 Activity 时解析为 true (2认同)