我有两个活动,A和B.当活动A首次启动时,它会访问传递给它的Intent
(因为Bundle
是null
,因为它应该是第一次通过),并相应地显示信息:
CustInfo m_custInfo;
...
protected void onCreate(Bundle savedInstanceState)
{
...
Bundle bundle = (savedInstanceState == null) ? getIntent().getExtras() : savedInstanceState;
m_custInfo = (CustInfo) m_bundle.getSerializable("CustInfo");
if (m_custInfo != null
...
}
第一次通过时效果很好。 <{1}}控件和EditText
已正确填写。
现在,当单击列表中的项目时,将启动活动B以显示详细信息:
ListView
在活动B开始之前,框架调用A覆盖m_custInfo = m_arrCustomers.get(pos);
Intent intent = new Intent(A.this, B.class);
intent.putExtra("CustInfo", m_custInfo); // CustInfo is serializable
// printing this intent, it shows to have extras and no flags
startActivityForResult(intent, 1);
:
onSaveInstanceState()
在活动B中,当在操作栏中按下向上按钮时,我想返回活动A并使其处于以前的状态:
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putSerializable("CustInfo", m_custInfo);
}
这就是问题,当活动A的public boolean onOptionsItemSelected(MenuItem item)
{
if (item.getItemId() == android.R.id.home)
{
Intent intent = NavUtils.getParentActivityIntent(this);
// printing this intent, it shows to have flags but no extras
NavUtils.navigateUpFromSameTask(this); // tried finish() here but that created an even bigger mess
return true;
}
...
}
第二次,onCreate()
参数为Bundle
且 null
返回{ {1}}。自调用getExtras()
以来,我原本期望null
参数为非onSaveInstanceState()
。
我在其他网站上看过这个问题,已经尝试了这些建议,但没有任何效果。
答案 0 :(得分:129)
如果您希望应用程序以这种方式做出反应,您应该将活动A的启动模式声明为:
android:launchMode="singleTop"
在AndroidManifest.xml中。
否则android使用标准启动模式,这意味着
“系统始终在中创建活动的新实例 目标任务“
并重新创建您的活动(请参阅Android documentation)。
使用singleTop,如果系统位于任务后堆栈的顶部,则系统将返回到您现有的活动(使用原始附加功能)。在这种情况下,无需实现onSaveInstanceState。
savedInstanceState在您的情况下为空,因为您的活动以前没有被操作系统关闭。
注意(感谢Android开发人员指向this):
虽然这是问题的解决方案,但如果返回的活动在后端堆栈的顶部而不是,它将无法工作。
考虑活动A起始B的情况,它开始于C,而C的父活动被配置为A.
如果从C调用NavigateUpFromSameTask()
,将重新创建活动,因为A不在堆栈顶部。
在这种情况下,可以使用这段代码:
Intent intent = NavUtils.getParentActivityIntent(this);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
NavUtils.navigateUpTo(this, intent);
答案 1 :(得分:17)
这是因为NavUtils.navigateUpFromSameTask()
基本上只是调用startActivity(intentForActivityA)
。如果活动A使用默认android:launchMode="standard"
,则会创建活动的新实例,并且不使用保存的状态。有三种方法可以解决这个问题,各种优点和缺点。
覆盖活动B中的getParentActivityIntent()并指定活动A所需的适当额外内容:
@Override
public Intent getParentActivityIntent() {
Intent intent = super.getParentActivityIntent();
intent.putSerializable("CustInfo", m_custInfo);
return intent;
}
注意:如果您正在使用ActionBarActivity和支持库中的工具栏,那么您需要覆盖getSupportParentActivityIntent(),而不是。
我认为这是最优雅的解决方案,因为无论用户如何导航到活动B,它都能正常工作。如果用户直接导航到活动B而不通过活动A,则下面列出的两个选项无法正常工作例如,如果从通知或URL处理程序启动活动B.我认为这种情况是出现这种情况的原因。导航API很复杂,并不像一个愚蠢的后退按钮。
此解决方案的一个缺点是使用标准的开始 - 新活动过渡动画而不是返回到先前活动的动画。
拦截向上按钮,并通过覆盖onNavigateUp()将其视为哑后退按钮:
@Override
public boolean onNavigateUp() {
onBackPressed();
return true;
}
注意:如果您正在使用ActionBarActivity和支持库中的工具栏,那么您需要覆盖onSupportNavigateUp(),而不是。
这个解决方案有点hacky,只适用于那些&#34; up&#34;和&#34;返回&#34;应该表现一样。这可能很少见,因为如果&#34; up&#34;和&#34;返回&#34;应该表现相同然后为什么打扰按钮?此解决方案的一个优点是使用标准的返回先前活动动画。
根据yonojoy的建议,在活动A上设置android:launchMode="singleTop"
。有关详细信息,请参阅his answer。请注意,singleTop
并不适合所有应用。您必须尝试和/或花一些时间阅读the documentation来自行决定。
答案 2 :(得分:4)
而不是调用NavUtils.navigateUpFromSameTask
您可以在导航之前获取父意图并进行修改。例如:
Intent intent = NavUtils.getParentActivityIntent(this);
intent.putExtra("CustInfo", m_custInfo); // CustInfo is serializable
NavUtils.navigateUpTo(this, intent);
这与NavUtils.navigateUpFromSameTask
的行为完全相同,但允许您为intent添加一些额外的属性。您可以查看NavUtils.navigateUpFromSameTask
的代码,这非常简单。
public static void navigateUpFromSameTask(Activity sourceActivity) {
Intent upIntent = getParentActivityIntent(sourceActivity);
if (upIntent == null) {
throw new IllegalArgumentException("Activity " +
sourceActivity.getClass().getSimpleName() +
" does not have a parent activity name specified." +
" (Did you forget to add the android.support.PARENT_ACTIVITY <meta-data> " +
" element in your manifest?)");
}
navigateUpTo(sourceActivity, upIntent);
}
使父活动SINGLE_TOP可能适用于某些简单的应用程序,但是如果此活动不是直接从它的父项启动的呢?或者您可能合法地希望父级存在于后台堆栈中的多个位置。
答案 3 :(得分:0)
我认为这是一个更通用的解决方案,可以添加到您的基本Activity类中:
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
if (item.getItemId() == android.R.id.home) {
final Intent upIntent = NavUtils.getParentActivityIntent(this);
if (upIntent == null)
onBackPressed();
else
//optionally add this flag to the intent: Intent.FLAG_ACTIVITY_SINGLE_TOP
NavUtils.navigateUpTo(this, upIntent);
return true;
}
return super.onOptionsItemSelected(item);
}
对于希望导航到某个特定父活动的每个活动,请在清单上使用它:
<activity android:parentActivityName="pathToParentActivity" ...>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="pathToParentActivity"/>
</activity>
并且,如果您的minSdk来自API 16,则删除“元数据”标记,因此您可以在清单中使用它:
<activity android:parentActivityName="pathToParentActivity" ...>
</activity>
更多信息here
答案 4 :(得分:-1)
你提到:
在活动B中,当在操作栏中按下向上按钮时,我想返回活动A并使其处于以前的状态。
如果活动A上的内容位于片段中,则在片段的onCreate()中调用setRetainInstance(true)。
然后,Fragment实例将在Activity娱乐中保留。