从使用navigateUpFromSameTask()的活动返回

我有两个活动A和B.当活动A第一次启动时,它访问传递给它的Intent (因为Bundlenull ,因为它应该是第一次通过),并相应地显示信息:

 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 ... } 

这是第一次通过罚款。 EditText控件和ListView被正确填写。

现在,当点击列表中的一个项目时,活动B开始显示细节:

 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); 

在活性B开始之前,框架调用A的重写onSaveInstanceState()

 protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putSerializable("CustInfo", m_custInfo); } 

在活动B中,当在操作栏中按下向上button时,我想要返回到活动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; } ... } 

这里存在这个问题,第二次在ActivityA的onCreate()时, Bundle参数为null getExtras()返回null 。 由于onSaveInstanceState()被调用,我会期望Bundle参数是非null

我已经阅读过有关这个问题的其他网站,已经尝试过的build议,但没有任何工作。

如果您希望您的应用程序以这种方式作出反应,则应声明您的活动A的启动模式为:

 android:launchMode="singleTop" 

在你的AndroidManifest.xml中。

否则android使用标准启动模式,这意味着

“系统总是在目标任务中创build一个活动的新实例”

并重新创build您的活动(请参阅Android文档 )。

使用singleTop时,如果系统位于任务的后退堆栈的顶部,系统将返回到您现有的活动(与原来的额外)。 在这种情况下,不需要实现onSaveInstanceState。

savedInstanceState在你的情况下为null,因为你的活动之前没有被操作系统closures。

注意 (感谢,Android开发人员指出)

虽然这是问题的解决scheme,但如果返回的活动不在返回堆栈的顶部,则不起作用 。 考虑活动的情况A开始B,开始C,并且C的父活动被configuration为A.如果你从C调用NavigateUpFromSameTask() ,活动将被重新创build,因为A不在栈顶。

在这种情况下,可以使用这段代码:

 Intent intent = NavUtils.getParentActivityIntent(this); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP); NavUtils.navigateUpTo(this, intent); 

发生这种情况是因为NavUtils.navigateUpFromSameTask()基本上只是调用startActivity(intentForActivityA) 。 如果活动A使用默认的android:launchMode="standard" ,则会创build一个活动的新实例,并且不使用保存的状态。 有三种方法可以解决这个问题,具有各种优点和缺点。

选项1

重写活动B中的getParentActivityIntent()并指定活动A所需的相应附加内容:

 @Override public Intent getParentActivityIntent() { Intent intent = super.getParentActivityIntent(); intent.putSerializable("CustInfo", m_custInfo); return intent; } 

注意:如果您使用ActionBarActivity和支持库中的工具栏,则需要重写getSupportParentActivityIntent() 。

我觉得这是最优雅的解决scheme,因为它的工作原理与用户如何导航到活动B无关。如果用户直接导航到活动B而不经过活动A,则下面列出的两个选项无法正常工作,例如活动B从通知或URL处理程序启动。 我认为这种情况是'up'导航API复杂的原因,并不仅仅是一个愚蠢的后退button。

这个解决scheme的一个缺点是使用标准的开始一个新的活动过渡animation,而不是返回到上一个活动的animation。

选项2

拦截向上button并通过覆盖onNavigateUp()将其视为沉默的后退button:

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

注意:如果您使用ActionBarActivity和支持库中的工具栏,则需要重写onSupportNavigateUp() 。

这个解决scheme有点怪异,只适用于“上”和“后”应该performance相同的应用程序。 这可能是罕见的,因为如果“上”和“后”应该performance相同,那么为什么还要有一个向上的button? 这个解决scheme的一个优点是使用标准的返回前一个活动animation。

选项3

正如yonojoy所build议的那样,在activity A上设置android:launchMode="singleTop" 。详见他的答案 。 请注意, singleTop不适用于所有应用程序。 你必须尝试和/或花一些时间阅读文档来自己决定。

而不是调用NavUtils.navigateUpFromSameTask

你可以得到父母的意图,并在导航之前进行修改。 例如:

 Intent intent = NavUtils.getParentActivityIntent(this); intent.putExtra("CustInfo", m_custInfo); // CustInfo is serializable NavUtils.navigateUpTo(this, intent); 

这将与NavUtils.navigateUpFromSameTask完全相同,但可以让您为意图添加一些额外的属性。 你可以看看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可能适用于一些简单的应用程序,但如果此活动不是直接从其父级启动的呢? 或者您可能合法地希望父代存在于后端堆栈中的多个位置。

你提到:

在活动B中,当在操作栏中按下“向上”button时,我想要返回到活动A并使其处于与之前相同的状态。

如果活动A上的内容驻留在Fragment中,则在Fragment的onCreate()中调用setRetainInstance(true)。

然后片段实例将保留在Activity休闲中。