简体   繁体   English

尽管调用onSaveInstance(),捆绑的saveInstanceState在onCreateView()中始终为null

[英]Bundle savedInstanceState always null in onCreateView() despite calling onSaveInstance()

I have FragmentA hosted by ActivityA . 我有由ActivityA托管的FragmentA When the user selects an item from the options menu, ActivityB is started which hosts FragmentB . 当用户从选项菜单中选择一个项目时,将启动承载FragmentB ActivityB For now, I want to retain a String and a boolean from FragmentA by overriding onSaveInstanceState() , so when the user returns to FragmentA , their information is preserved. 现在,我想通过重写onSaveInstanceState()FragmentA保留一个String和一个boolean ,因此当用户返回FragmentA ,将保留其信息。

Code from FragmentA : 来自FragmentA代码:

@Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
    //LOGS SHOW THAT THIS IS ALWAYS CALLED WITH CORRECT VALUES
    super.onSaveInstanceState(savedInstanceState);
    savedInstanceState.putString("string", "example");
    savedInstanceState.putBoolean("boolean", bool);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
{
    View v = inflater.inflate(R.layout.fragmentA, parent, false);

    //LOGS SHOW THAT THIS IS ALWAYS NULL
    if (savedInstanceState != null)
    {
        if (savedInstanceState.getString("text") != null)
        {
            mObject.setText(savedInstanceState.getString("string"));
        }

        bool = savedInstanceState.getBoolean("boolean");
    }

    ...
}

From reading previous problems similar to mine: 通过阅读以前与我类似的问题:

1) I decided to place the code to recover the information in onCreateView() because onCreate() will not always be called. 1)我决定将代码恢复到onCreateView()因为不会总是调用onCreate() (Although tests with the code in onCreate() also have the same problem.) (尽管使用onCreate()的代码进行测试也存在相同的问题。)

2) I also did not call setRetainInstance(true) , since this will cause Bundle savedInstanceState to always be null . 2)我也没有调用setRetainInstance(true) ,因为这将导致Bundle savedInstanceState始终为null

3) I made sure that the XML layout for FragmentA has an id. 3)我确保FragmentA的XML布局具有ID。 The various children elements of this layout also have ids. 此布局的各种子元素也具有ID。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragmentA"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"> 

    ...
</LinearLayout>

Despite this, Bundle savedInstanceState is always null. 尽管如此, Bundle savedInstanceState始终为null。 What am I missing here? 我在这里想念什么?

Any help appreciated. 任何帮助表示赞赏。 Thanks! 谢谢!

The savedInstanceState is null when no data was been previously saved. 如果以前没有保存任何数据,则savedInstanceState为null。 To save data you must override the onSaveInstanceStateBundle(Bundle) method as described in the Android documentation: 要保存数据,您必须按照Android文档中的说明覆盖onSaveInstanceStateBundle(Bundle)方法:

you should use the onPause() method to write any persistent data (such as user edits) to storage. 您应该使用onPause()方法将任何持久性数据(例如用户编辑)写入存储。 In addition, the method onSaveInstanceState(Bundle) is called before placing the activity in such a background state, allowing you to save away any dynamic instance state in your activity into the given Bundle, to be later received in onCreate(Bundle) if the activity needs to be re-created. 另外,在将活动置于这样的背景状态之前,将调用onSaveInstanceState(Bundle)方法,从而使您可以将活动中的任何动态实例状态保存到给定的Bundle中,如果活动被以后在onCreate(Bundle)中接收需要重新创建。 See the Process Lifecycle section for more information on how the lifecycle of a process is tied to the activities it is hosting. 有关流程的生命周期如何与其托管的活动联系在一起的更多信息,请参见流程生命周期部分。 Note that it is important to save persistent data in onPause() instead of onSaveInstanceState(Bundle) because the latter is not part of the lifecycle callbacks, so will not be called in every situation as described in its documentation. 请注意,将持久性数据保存在onPause()中而不是onSaveInstanceState(Bundle)中非常重要,因为后者不是生命周期回调的一部分,因此不会在文档中描述的每种情况下都调用它。

More info here 更多信息在这里

Use the onPause() to save your persistent data, that's referring to data that you would like to keep permanently, and hence, you save it in your SharedPreferences or your Database . 使用onPause()保存您要持久保存的数据,即要永久保存的数据,因此可以将其保存在SharedPreferencesDatabase onSaveInstanceState on the other hand retrains the data in case an activity is destroyed and you'd like to get that data back, a good scenario would be a user filling in a form. 另一方面,如果活动被破坏并且您想取回数据,则onSaveInstanceState数据,一个好的情况是用户填写表单。 You said in your example that you're navigating from Activity A to Activity B , then you go back to Activity A , when you first navigate, Activity A is not destroyed, it's only sent to the background, so when you return to it, it's already there and will be brought to the foreground, your values should actually be there unchanged, and onCreate and onCreateView will not be called as the Activity is still alive (although it might be killed in case of low memory on device). 您在示例中说过,您要从Activity A导航到Activity B ,然后回到Activity A ,当您第一次导航时, Activity A并没有被销毁,只是发送到了后台,所以当您返回到后台时,它已经存在并且将被带到前台,您的值实际上应该保持不变,并且不会调用onCreateonCreateView因为Activity仍然有效(尽管在设备内存不足的情况下可能会被杀死)。

Best and fastest way to test your onSaveInstanceState is the most often used scenario, Orientation Change , orientation change will cause the activity to get destroyed completely and re-created, so allow orientation change on Activity A , put some values in your saveStateBundle and rotate the device, now this will call all your methods from the start, onCreate , onCreateView , ... etc to create the activity with the appropriate layout, your savedInstanceState should not be null now. 最好的和最快的测试onSaveInstanceState是最常用的方案, Orientation Change ,方向更改将导致活动被完全破坏并重新创建,因此允许在Activity A上更改方向,将一些值放在saveStateBundle并旋转设备,现在它将从头开始调用所有方法onCreateonCreateView等,以创建具有适当布局的活动,您的savedInstanceState现在不应为null。

Note this is assuming your application is staying alive, if you're going to close the app completely and still want to keep the data, then put your information in the SharedPreferences or Database and retrieve them when you start the app again. 请注意,这是假设您的应用程序仍在运行中,如果您要完全关闭该应用程序并且仍然想要保留数据,则将您的信息放入SharedPreferencesDatabase ,并在再次启动该应用程序时检索它们。

// Edit 1 //编辑1

to show you how to store values in SharedPreferences anywhere in your application, these values are persistent even if your application is closed. 为了向您展示如何在应用程序中的任何位置将值存储在SharedPreferences中,即使关闭了应用程序,这些值也将保持SharedPreferences (although onSaveInstanceState should be enough to what you're looking for but hope this helps) (尽管onSaveInstanceState应该足以满足您的需求,但希望对您有所帮助)

// SharedPreference
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
// Storing
preferences.edit().putString("valueNameOrKey", StringValue).commit();
// Retrieving
preferences.getString("valueNameOrKey", defaultValueToReturnInCaseThatKeyIsNotFound);

// Edit 2 //编辑2

To remove any key/value pair from the SharedPreferences you can do this: 要从SharedPreferences中删除任何键/值对,可以执行以下操作:

preferences.edit().remove("valueNameOrKey").commit();

But then pay attention to what happens when you retrieve the value, since the key will not be available, it's going to return the default value instead like this: 但是,请注意在检索值时会发生什么,因为键将不可用,因此它将返回默认值,如下所示:

preferences.getString("valueNameoOrKey", ""); // "" Is my default value since I'm using a String

since you can use putString, putInt, putBoolean etc, same goes for the get functions, your default value must match the expected return type. 由于您可以使用putString,putInt,putBoolean等,因此对于get函数也是如此,因此您的默认值必须与预期的返回类型匹配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM