在Fragment中,SavedInstanceState始终为空。

38

我在活动中使用 XML(和 activity 中的 setContentView())将一个片段附加到其中。我有一个问题,因为我的片段中有非常动态的视图,所以当方向改变时,我必须恢复所有视图的状态。

我有问题,因为我正在使用类似以下内容的东西:

public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean("restore", true);
        outState.putInt("nAndroids", 2);
   }

但是在屏幕方向改变后,像onCreateView等带有参数Bundle savedInstanceState的方法被调用时,我的savedInstanceState总是为空。

我在Android方面不是新手,但现在因为这个问题非常生气...

public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    if (savedInstanceState == null) {
        //smth
    } else {
        // smthelse THIS IS NEVER REACHED BECAUSE BUNDLE IS ALWAYS NULL
    }

    getListView().setDivider(getResources().getDrawable(R.drawable.list_divider));
}

1
在Activity中使用onSaveInstanceState方法时,一切正常。但是在XML布局中附加的Fragment中保存Bundle时出现了问题... - TommyNecessary
你能在Fragment的OnCreate方法中发布你的代码吗? - znat
我在文章结尾处添加了。 - TommyNecessary
@TommyNecessary:“我在Android方面不是新手,但现在因为这个问题非常生气...”:> - Kapparino
6个回答

65

问题出在我没有在XML中为片段声明android:id。Android需要ID或标记来识别存储的片段并重新生成其中的所有元素。所以各位,记住 - 每个片段实例都需要唯一的ID或标记!

此外,当声明setRetainInstance(true)时,bundle应始终返回null。


9
你能展示一下你的代码是怎样的吗?我不确定你是如何/在哪里将xml ID与你的Fragment Activity 相连的。 - Azurespot
3
请问您能否说明如何在XML中指定片段ID? - babay
2
@babay:很简单:<fragment android:id="@+id/your_id" .../> - TommyNecessary
13
谢谢。那动态添加的片段(使用FragmentManager事务添加的片段)怎么办?我发现唯一的方法是在Fragment的参数中存储状态... - babay
4
回答 @babay 的问题:关于编程 / 动态添加片段,我也遇到了同样的问题:每次尝试恢复标准 savedInstanceState 时,它总是为空。原因是我在使用 popBackStack,所以 onSaveInstanceState 方法从未被调用,因为它在 onDestroy 后执行,而不是在 onDestroyView 后执行,所以 Fragment 中的 savedInstanceState 总是为空。解决方法很简单:创建一个私有 Bundle,在 onPause 中保存视图状态,然后在 onCreateView 中恢复它即可。 - Javi
显示剩余2条评论

7
我遇到了类似的问题,即使向片段提供了Bundle,savedInstanceState仍然为null。对我有效的唯一解决方案是执行以下操作:
myFragment.setArguments(bundle) 

使用从Activity中获取的bundle并执行

Bundle bundle = this.getArguments();

在片段的onCreateView中。

希望这能帮助其他人。


8
如果你从 Activity 设置参数,savedInstanceState 始终会返回 null。Activity 中的 bundle 和 savedInstanceState bundle 没有任何关联。 WTF 表示"什么鬼",不是一个正式的词语。 - Rakesh Yadav

2

针对片段(Fragment):

use this for save state of fragment on orientation.

onCreate(Bundle save)
{
   super.onCreate(save);
   setRetainInstance(true);
}

请查看此教程: http://techbandhu.wordpress.com/2013/07/02/android-headless-fragment/ 对于Activity: 当您启动应用程序时,在onCreate中,您的bundle对象为null,因此您必须像下面这样进行检查,当您旋转屏幕时,onSaveInstance被调用并且您的bundle对象被初始化。
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_game);

    if (savedInstanceState != null) {
         boolean t = outState.getBoolean("restore"); 
         int s = outState.getInt("nAndroids");
    }
}

1
我理解这个情况,但在 activity 实例中我没有遇到此问题。当我像您一样执行某些操作时,我可以从 bundle 中获取好的值,但是在 fragment 中,即使我在 fragment 实例的 onSavedInstanceState 方法中放置了值,savedInstanceState 仍为空。 - TommyNecessary

1

首先,您应该放置您的数据,然后调用super.onSaveInstanceState(outState);

public void onSaveInstanceState(Bundle outState) {

    outState.putBoolean("restore", true);
    outState.putInt("nAndroids", 2);
    super.onSaveInstanceState(outState);
}

请确保该活动在AndroidManifest.xml中没有nohistory属性,或将其设置为false
        <activity
        android:noHistory="false">

1

好的,我知道这是一篇旧文章,但我在这里和许多其他地方都找不到合适的答案,所以我要发表如何解决我的问题。

所以我的片段(Fragment)在一个活动(Activity)中。我最初尝试仅在片段中保存Bundle,并在onCreateView中检索它。然而,那就是问题所在。

我通过在活动中初始化myFragment对象并将该对象放入activity Bundle中的onSaveInstanceState()来解决了这个问题。然后在onRestoreInstanceState()中检索它。我使用了getSupportFragmentManager().putFragment/getFragment。然后片段中的savedInstanceState不再为null。


1
我和navGraph片段有类似的问题。在onSaveInstanceState() onSaveInstanceState()不是null,但在onCreate时它是null,并且onRestoreInstanceState()根本没有被调用。 - Reijo Korhonen

1
如果您正在尝试使用outState保存状态并通过导航到另一个片段来销毁该片段,则此方法将不起作用。在这种情况下,您需要永久地保存状态,可以使用sharedPreferences,如果状态较大且您想要更有组织,您可以使用任何持久化库,如Room,Realm等等。
只有在Fragment/Activity需要在配置更改(例如旋转)或进程被操作系统杀死(例如应用在后台)时才应该使用outState和savedInstanceState。

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