savedInstanceState始终为null


73

这是我的saveInstaceState代码:

@Override
public void onSaveInstanceState(Bundle savedInstanceState) 
{
    savedInstanceState.putStringArrayList("todo_arraylist", Altodo);
    Log.v("bundle", "Saved");
    super.onSaveInstanceState(savedInstanceState);
}


public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);

    if (savedInstanceState != null) 
    {
        Altodo = savedInstanceState.getStringArrayList("todo_arraylist");
        Log.v("bundle", "Restored");
    }
    else
    {
        Log.v("bundle", "null");
    }

    setContentView(R.layout.main);
}

日志始终显示“捆绑保存”标签。

但是在onCreate方法中,SavedInstanceState始终为null。


2
您需要先将super.onSaveInstanceState(savedInstanceState)调用,然后再将您的值添加到Bundle中,否则在该调用中它们将被清除(Droid X And​​roid 2.2)。
AndroidGeek

2
我遇到了同样的问题,可以确认这不起作用。有人解决了吗?
Jim Clermonts 2014年

Answers:


53

在一个活动AB扩展了两个项目中,我观察到了完全相同的症状(报告为问题133394)。活性是主要的活性,我总是接收用于在其列表片段从一个详细视图活动返回时。几个小时后,这个问题以变相的导航问题暴露给我。ActionBarActivitynullsavedInstanceStateonCreate

以下内容可能与我的设置有关,并且来自此页面上的其他答案:

  • 有了这个答案,我确保每个片段和活动都有唯一的ID集。
  • 没有onSaveInstanceState没有super呼叫的覆盖。
  • 活动A被指定为A中的活动B的父级AndroidManifest.xml,同时使用android:parentActivityName属性和meta-data早期Android版本的相应标签(请参见“提供导航”)。

getActionBar() .setHomeButtonEnabled(true)活动B已经没有任何相应的创建代码(如),在其操作栏中有一个正常的后退按钮(<)。轻按此按钮后,活动A重新出现,但(a)所有先前实例状态都丢失,(b) onCreate始终被调用,并且(c) savedInstanceState始终null

有趣的是,当我点击仿真器显示屏底部边缘处的后退按钮(指向左侧的空心三角形)时,活动A再次出现,就像它离开时一样(即实例状态完全保留),而没有调用onCreate。因此,导航可能有问题吗?

经过多看书,我实现了我自己的导航指令响应在活动的后退按钮自来水运行

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == android.R.id.home)
        NavUtils.navigateUpFromSameTask(this);
        return true;
    }
    return super.onOptionsItemSelected(item);
}

与恢复活动A的实例状态无关。NavUtils还提供了一种方法getParentActivityIntent(Activity)navigateUpTo(Activity, Intent)该方法允许我们通过设置标志来修改导航意图,以明确指示活动A并非重新开始(因此未提供已保存的实例状态)FLAG_ACTIVITY_CLEAR_TOP

如果已设置,并且正在启动的活动已在当前任务中运行,那么与其启动该活动的新实例,不如关闭该活动之上的所有其他活动,并将此Intent传递给(现在顶部)将旧活动作为新的Intent。

在我手中,这解决了实例状态丢失的问题,可能看起来像:

public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId()== android.R.id.home) {
        Intent intent = NavUtils.getParentActivityIntent(this);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        NavUtils.navigateUpTo(this, intent);
        return true;
    }
    return super.onOptionsItemSelected(item);
}

请注意,在用户可以从其他任务中直接切换到活动B的其他情况下,这可能不是完整的解决方案(请参见此处)。另外,一种不使用行为的可能相同的解决方案NavUtils是简单地调用finish()

public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId()== android.R.id.home) {
        finish();
        return true;
    }
    return super.onOptionsItemSelected(item);
}

两种解决方案都在我手中。我只是在推测原始问题是后退按钮的默认实现稍有不正确,并且可能与调用某种navigateUp未命中的实现有关FLAG_ACTIVITY_CLEAR_TOP


1
太棒了 我使用您提供的最后一个解决方案将其实施到我的基本活动中,但是我将其替换finish();onBackPressed();
安德里亚·拉扎罗托

2
这个答案对我很有帮助!我仍然不确定为什么操作栏后退按钮的行为与设备后退按钮的行为不同,但是一旦我android:launchMode="singleTop"在AndroidManifest.xml中添加了Activity的XML定义后,它就会开始持续工作。根据文档,这FLAG_ACTIVITY_CLEAR_TOP与您完成的添加基本​​上相同。
JHS

finish();每次启动另一个活动时打电话是有效的吗?有没有更好的选择?
伊利亚·莫克

1
2020而且我仍然遇到这个错误。荒谬。Google将该问题133394忽略了5年,直到2020年4月,然后“因为不会修复已过时”将其关闭。感谢您的全面答复;最后的onOptions ... finish()blob为我修复了它。看来您的解决方案将在相当长的一段时间内成为唯一解决方案。再次感谢,在我拔头发几天之后,您救了我。
尤里尔

14

您是否检查了该视图的ID(如果有/是否有...)。否则不会调用onSaveInstanceState()。

检查此链接


3
这个答案似乎与所问的问题无关。Med指出,始终会调用onSaveInstanceState(),因此问题不在于不调用onSaveInstanceState()
P1x

13

以这种方式保存的状态不会持久。如果您像在调试期间一样杀死了整个应用程序,则捆绑包中的始终为null onCreate

该IMO是糟糕的Android文档的另一个示例。这也是为什么市场上大多数应用程序无法(完全)正确实现保存状态的原因。


2
所以这仅用于屏幕方向更改等吗?
Fabian Zeindl

7
我完全同意“糟糕的文档”。
Fabian Zeindl

1
Fabian,理论上,当活动被销毁然后重新创建时,仍将创建保存的状态,这是无法测试的。IME确实发生了这种用例。
mxcl

我知道。但是,当我阅读Bundle时,我的第一个念头是,这是从应用程序存储状态的主要/默认/最简单的方法。并不是说它在“边缘情况”中使用。
Fabian Zeindl

3
它看起来像一个错误,因为文件明确地说,当破坏活动状态,即使保存developer.android.com/guide/components/...我创建的问题code.google.com/p/android/issues/detail?id = 133394
西蒙(Simon)

8

在清单中添加此行用于活动

android:launchMode="singleTop"

例如:

<activity
        android:name=".ActivityUniversity"
        android:label="@string/university"
        android:launchMode="singleTop"
        android:parentActivityName="com.alkhorazmiy.dtm.ActivityChart">
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.alkhorazmiy.dtm.ActivityChart" />
    </activity>

1
指定此行对活动到底有什么作用?
大卫读了

3

您如何测试?

Imo最好的测试方法是使用“设置”>“开发人员选项”中的“不保留活动”标志。如果“设置”中没有“开发人员选项”,请参阅“启用设备上的开发人员选项”

  1. 开启你的活动
  2. 长按首页
  3. 转到另一个应用程序
  4. 长按首页
  5. 返回您的应用

DevTools仅在仿真器中工作。如果要使用相同的方法在真实设备上进行测试,请使用SetAlwaysFinish工具。请参阅此答案以获取更多详细信息:stackoverflow.com/a/8621269/483708
Theo

现在,开发人员选项在所有设备上都可用。
本杰明



0

要进行调试,请考虑实现onRestoreInstanceState并在此方法中调用Log.d。然后,在模拟器中,按ctrl-F11或其他按钮旋转手机。您对Log.d的呼叫应该被点击。


1
我已将log.v更改为log.d,但从未成功。
配有

@med如果您在单个活动中未在方向更改时调用onRestoreInstanceState,则您的情况可能比我们理解的要复杂。我在这里有一些代码:sites.google.com/site/jalcomputing/home/…–



0

香港专业教育学院设法以同样的方式。我没有在onCreateView方法上处理saveInstanceState Bundle,而是在onCreate方法上对其进行处理,并将传递的值设置为globar变量,然后在onCreateView方法上访问此变量。希望能帮助到你。



0

我能够用以下方法解决它:

@Override public boolean onSupportNavigateUp()
{
    onBackPressed();
    return true;
}

清单中仍设置了父级。因此,当您按下向上导航按钮时,它的作用类似于后退按钮。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.