我在一个拥有两个继承自ActionBarActivity
的活动(A和B)的项目中观察到了完全相同的症状(作为问题133394报告)。 Activity A 是主活动,在从详细视图活动B返回时,我总是在其列表片段的onCreate
中收到null
的savedInstanceState
。经过多个小时的调试,这个问题最终表现为一个伪装成导航问题。
以下与我的设置相关且来自本页其他答案:
- 根据此答案,我确保每个片段和活动都设置了唯一的ID。
- 没有在调用父函数的情况下重写
onSaveInstanceState
。
- 在
AndroidManifest.xml
中指定活动A为活动B的父级,使用android:parentActivityName
属性和早期版本的Android对应的meta-data
标签(参见“提供向上导航”)。
即使没有任何相应的创建代码,例如getActionBar().setHomeButtonEnabled(true)
,活动B在其操作栏中具有一个可用的后退按钮(<)。当点击该按钮时,活动A会重新出现,但是其所有之前的实例状态都会丢失(a)、始终调用onCreate
(b),并且savedInstanceState
始终为null
(c)。
有趣的是,当我点击模拟器显示器底部提供的返回按钮(指向左侧的打开三角形),活动A会以原样重新出现(即其实例状态完全保留),而不会调用onCreate
。所以也许导航存在问题?
经过更多阅读,我执行了自己的导航指令,以响应在活动B中的返回按钮上的轻按:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home)
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
与恢复活动状态无关的内容并没有改变。 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);
}
这两种解决方案在我的手中都有效。我只是推测最初的问题是后退按钮有些不正确的默认实现,可能与该实现调用某种未包含FLAG_ACTIVITY_CLEAR_TOP
的navigateUp
有关。