向上导航打破了果冻豆?

源代码可在这里find: https : //github.com/novemberox/NavigationTest这是这个样本的修改版本: http : //developer.android.com/training/implementing-navigation/ancestral.html

我有三个活动:

  • Main Activity只是主要入口申请
  • Category Activity它是“细节活动”的父项
  • Detail Activity

Main Activity有打开Category ActivityDetail Activitybutton。 Category Activty只有一个button,打开Detail Activity 。 最后,显示一些文本的Detail Activity ,并有button,模拟点击ActionBar了。

我的“点击”path是:

  • 打开主要活动
  • 打开细节活动
  • 点击“向上button”
  • 应该出现类别激活
  • 后退单击将我们移动到主要活动状态恢复

这是预期的stream量,并且在Jelly Bean(在Galaxy Nexus 4.1.1和仿真器4.2 Google exp包中testing)之前,它在每个Android上都工作得很好。 它甚至可以在ICS上运行。 我正在使用支持库和像NavUtils和TaskStackBuilder类,就像我在开始时指出的示例。

在JB上,当我点击“向上button”时,它会返回到主要活动状态恢复正确。 我查看了支持库的源代码,我看到NavUtils.navigateUpTo方法调用本地JB代码,如Activity#navigateUpTo 。 我尝试了NavUtils#navigateUpTo()NavUtils.navigateUpFromSameTask() ,同样的不满意的结果。

你有什么build议怎么做才能有这个好的stream量?

首先,如果您的设备的目标设备与API 17(Android 4.2)一样高,请在清单中将targetSdkVersion设置为17。 这不会中断对旧设备的支持,只会让新设备正常工作。 当然,这并不能解决你的问题 – 这只是一个好的做法。

你应该使用什么?

我假设你是基于你的代码从这个页面的祖先导航示例。 你已经使用了第二个例子:

 Intent upIntent = new Intent(this, MyParentActivity.class); if (NavUtils.shouldUpRecreateTask(this, upIntent)) { // This activity is not part of the application's task, so create a new task // with a synthesized back stack. TaskStackBuilder.from(this) .addNextIntent(new Intent(this, MyGreatGrandParentActivity.class)) .addNextIntent(new Intent(this, MyGrandParentActivity.class)) .addNextIntent(upIntent) .startActivities(); finish(); } else { // This activity is part of the application's task, so simply // navigate up to the hierarchical parent activity. NavUtils.navigateUpTo(this, upIntent); } 

但是,对于您想要的行为,您需要将NavUtils.navigateUpToreplace为:

 upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(upIntent); finish(); 

为什么它在ICS和早期版本上工作?

一般来说,支持库试图近似在后面的API中引入的行为。 在NavUtils的情况下,支持库试图近似API 16(又名Android 4.1)中引入的行为。 对于API 16之前的平台, NavUtils使用:

 @Override public void navigateUpTo(Activity activity, Intent upIntent) { upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); activity.startActivity(upIntent); activity.finish(); } 

这通过back stack来查看upInent指定的活动的实例。 如果它find一个,就清除一切并恢复它。 否则,它只是启动活动。

在API 16+以后的平台上,支持库把事情交给Activity API的本地调用。 根据文件:

public boolean navigateUpTo(Intent upIntent)

从此活动导航到由upIntent指定的活动,在此过程中完成此活动。 如果upIntent指示的活动已经存在于任务的历史logging中,则该活动以及历史堆栈中指示的活动之前的所有其他活动将被完成。

如果指示的活动未出现在历史堆栈中,则将完成此任务中的每个活动,直到达到任务的根活动 ,导致“应用程序内主页”行为。 这对于具有复杂导航层次结构的应用程序可能非常有用,当活动可能通过不通过规范父活动的path到达时。

从那以后,如果它不在回栈中,它是否会启动在upIntent指定的活动还不清楚。 阅读源代码也无助于澄清事情。 但是,从您的应用程序正在显示的行为来看,它似乎不会尝试启动upIntent活动。

无论哪种实现是对还是错,最终的结果都是您需要FLAG_ACTIVITY_CLEAR_TOP行为,而不是本机API 16的行为。 不幸的是,这意味着你将不得不复制支持库的近似值。

哪个是对的?

免责声明:我不为Google工作,所以这是我最好的猜测。

我的猜测是,API 16+行为是预期的行为; 这是一个内置的实现,可以访问Android的内部,并可以做的事情是不可能通过API。 在API 16之前,我不认为有可能以这种方式展开堆叠,而不是使用意向标志。 因此, FLAG_ACTIVITY_CLEAR_TOP标志是可用于预API 16平台的API 16行为的最接近的近似值

不幸的是,原生实现和支持库实现之间的结果是违反了在你的场景中最不惊讶的原则 。 这导致我怀疑这是否是API的意外使用。 也就是说,我想知道Android是否期望您遍历一个活动的完整导航path,而不是直接跳转到该活动。

以防万一

只是为了避免一个可能的误解,有人可能会认为shouldUpRecreateTask来奇迹般地确定父代不在后端堆栈中,并使用TaskStackBuilder为您合成所有内容的过程。

但是, shouldUpRecreateTask基本上决定了您的应用程序是否直接由您的应用程序启动(在这种情况下返回false ),或者从其他应用程序启动(在这种情况下返回true )。 在这本书中 ,支持库检查intent的“action”是不是ACTION_MAIN (我没有完全理解),而在API 16平台上,它是基于任务关系执行检查的。 不过,在这个应用程序的情况下,事情解决办法shouldUpRecreateTask返回false。

阅读@ cyfur01的回答后,我想出了一个非常简单的解决scheme,修复了这个问题。

在你的Activity中覆盖这个方法(或者理想的情况是在一些BaseActivity中为所有的子类修复),它应该像预期的那样工作:

 @Override public boolean navigateUpTo(Intent upIntent) { boolean result = super.navigateUpTo(upIntent); if (!result) { TaskStackBuilder.create(this) .addNextIntentWithParentStack(upIntent) .startActivities(); } return result; } 

它将所有工作都留给了Android实现,然后只检查navigateUpTo(upIntent)返回值,当找不到指定活动的实例时,这个返回值是false并且此活动正常结束 。 当我们想要手动创build和启动父活动时,情况正是如此。 另外请注意,我们不必在这里调用finish() ,因为它是由super方法调用的。