首先,如果您的目标设备高达 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.navigateUpTo
为:
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();
}
这会在后台堆栈中查找 中指定的活动实例upInent
。如果它找到一个,它会清除它的所有内容并恢复它。否则它只会启动活动。
在 API 16+ 更高版本的平台上,支持库将事情交给Activity
API 中的本机调用。根据文档:
public boolean navigateUpTo (Intent upIntent)
从这个活动导航到 upIntent 指定的活动,在流程中完成这个活动。如果 upIntent 指示的活动已经存在于任务的历史中,则该活动以及历史堆栈中指示的活动之前的所有其他活动都将完成。
如果指示的活动没有出现在历史堆栈中,这将完成此任务中的每个活动,直到到达该任务的根活动,从而产生“应用内主页”行为。这在具有复杂导航层次结构的应用程序中很有用,当一个 Activity 可以通过不通过规范父 Activity 的路径到达时。
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是否希望您遍历活动的完整导航路径,而不是直接跳转到它。
以防万一
只是为了避免一种可能的误解,有人可能会期望shouldUpRecreateTask
神奇地确定父级不在后台堆栈中,并使用TaskStackBuilder
.
但是,shouldUpRecreateTask
基本上确定您的活动是由您的应用程序直接启动(在这种情况下它返回false
),还是它是从另一个应用程序启动的(在这种情况下它返回true
)。从这本书中,支持库检查意图的“动作”是否不是ACTION_MAIN
(我不完全理解),而在 API 16 平台上,它会根据任务关联性执行此检查。尽管如此,在这个应用程序的情况下,事情的结果是shouldUpRecreateTask
返回 false。