为什么不分段保持状态时,屏幕旋转?(Why won't Fragment retain st

2019-07-17 21:57发布

我已经有一些麻烦一个PreferenceFragment内的一些定制DialogPreference子当屏幕旋转时仍然可见。 使用PreferenceActivity时,我不会遇到这个问题,所以我不知道它是否是一个Android的bug或我的代码有问题,但我想有人来确认它们是否具有相同的体验。

为了测试这一点,首先创建包含至少一个DialogPreference偏好屏幕(它并不重要的亚类)。 然后在PreferenceActivity显示它。 当你在DialogPreference运行你的应用,按所以它的对话节目。 然后旋转屏幕,这样的方向变化。 是否该对话框保持可见?

然后尝试相同,但有一个PreferenceFragment,以显示自己的喜好,而不是PreferenceActivity。 再次,不对话框保持可见,当你旋转屏幕?

到目前为止,我发现,如果使用的是PreferenceActivity对话框将保持可见,但如果使用的是PreferenceFragment没有。 综观为DialogPreference源代码 ,它似乎是正确的行为是在对话框中保持可见,因为isDialogShowing是当被保存的状态信息onSaveInstanceState()被调用屏幕上的重新定位。 因此,我认为错误可能会阻止PreferenceFragment(和里面的一切吧)从恢复中的状态信息。

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

是否有人可以证实? 如果它不是一个错误,那么这是怎么回事?

Answer 1:

最后想出了一个解决这个问题。 原来,这是不是一个错误,但是在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();
    }
} 

这样做的问题是,当您更改屏幕方向(或破坏任何其他行动重新创建活动),您PreferenceFragment将获得创建两次 ,这是什么原因导致它失去了状态。

第一创建将经由活动的呼叫发生super.onCreate()如上所示),这将调用onActivityCreated()方法用于您的PreferenceFragment()和onRestoreInstanceState()中所包含的每个偏好的方法。 这将成功地恢复所有的一切的状态。

但随后一旦这一号召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();
        }
    }
}

或者换个方式是简单地检查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();
        }
    }
}

所以我想在这里学到的教训是onCreate()具有双重作用-它可以建立一个活动的第一次,也可以从以前的状态恢复。

答案在这里使我实现了这个解决方案。



Answer 2:

我确实有过这样的问题我自己。 还有一种情况的一个错误DialogFragment ,因为它是空没有恢复状态,或者至少它发生在我身上。

使用多个来源我最终得到了一个解决方案工作。 让你的对话框扩展这个BaseDialogFragment

import android.app.Dialog;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.support.v4.app.DialogFragment;

import com.actionbarsherlock.app.SherlockDialogFragment;

public class BaseDialogFragment extends DialogFragment {

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        if (savedInstanceState == null || savedInstanceState.isEmpty())
            savedInstanceState = WorkaroundSavedState.savedInstanceState;

        setRetainInstance(true);
        Log.d("TAG", "saved instance state oncreate: "
                + WorkaroundSavedState.savedInstanceState);
        super.onCreate(savedInstanceState);
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState)
    {
        if (savedInstanceState == null || savedInstanceState.isEmpty())
            savedInstanceState = WorkaroundSavedState.savedInstanceState;
        Log.d("TAG", "saved instance state oncretaedialog: "
                + WorkaroundSavedState.savedInstanceState);

        return super.onCreateDialog(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if (savedInstanceState == null || savedInstanceState.isEmpty())
            savedInstanceState = WorkaroundSavedState.savedInstanceState;

        Log.d("TAG", "saved instance state oncretaeview: "
                + WorkaroundSavedState.savedInstanceState);

        return super.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public void onDestroyView() // necessary for restoring the dialog
    {
        if (getDialog() != null && getRetainInstance())
            getDialog().setOnDismissListener(null);

        super.onDestroyView();
    }

    @Override
    public void onSaveInstanceState(Bundle outState)
    {
        // ...

        super.onSaveInstanceState(outState);
        WorkaroundSavedState.savedInstanceState = outState;
        Log.d("TAG", "saved instance state onsaveins: "
                + WorkaroundSavedState.savedInstanceState);

    }

    @Override
    public void onDestroy()
    {
        WorkaroundSavedState.savedInstanceState = null;
        super.onDestroy();
    }

    /**
     * Static class that stores the state of the task across orientation
     * changes. There is a bug in the compatibility library, at least as of the
     * 4th revision, that causes the save state to be null in the dialog's
     * onRestoreInstanceState.
     */
    public static final class WorkaroundSavedState {
        public static Bundle savedInstanceState;
    }
}

请注意,在其方法有任何子类savedInstanceState参数,您可能需要调用super与WorkaroundSavedState.savedInstanceState 。 而当你在恢复状态(即onCreate()只是忽略savedInstanceState ,而使用WorkaroundSavedState.savedInstanceState ,静态持有人是不干净的解决方案,但它的作品。只要确保将其设置为空在你onDestroy()

在任何情况下,我DialogFragment当我旋转屏幕(这还没有任何不消失configChanges )。 让和我知道,如果这个代码解决您的问题,如果没有,我会看看发生了什么事情。 另外请注意,我没有这个测试中PreferenceFragment而是其他Fragment从兼容S级或ActionBarSherlock



文章来源: Why won't Fragment retain state when screen is rotated?