Ответ 1
Прежде всего, если вы нацеливаете устройства на уровень API 17 (Android 4.2), установитеtargetSdkVersion
на 17 в манифесте. Это не нарушает поддержку старых устройств, а просто улучшает работу устройств на новых устройствах. Конечно, это не исправить вашу проблему - это просто хорошо сделать.
Что вы должны использовать?
Я предполагаю, что вы основываете свой код на примере Ancestral Navigation на этой странице. Вы использовали второй пример:
Intent upIntent = new Intent(this, MyParentActivity.class);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
// This activity is not part of the application 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 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
библиотека поддержки пытается аппроксимировать bahavior, введенную в API 16 (a.k.a. Android 4.1). Для платформ pre-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+ более поздняя версия поддерживает библиотеку поддержки, которая передает информацию в свой собственный вызов в API Activity
. Согласно документам:
public boolean navigateUpTo (Intent upIntent)
Перейдите от этой операции к активности, указанной upIntent, завершив эту операцию в этом процессе. Если активность, указанная upIntent, уже существует в истории задач, это действие и все остальные до указанного действия в стеке истории будут завершены.
Если указанное действие не отображается в стеке истории, это завершит каждое действие в этой задаче до тех пор, пока не будет достигнута корневая активность задачи, что приведет к поведению "в доме", Это может быть полезно в приложениях со сложной навигационной иерархией, когда активность может быть достигнута путем, не проходящим через каноническую родительскую активность.
Из этого неясно, начнет ли он действие, указанное в upIntent
, если оно не находится в фоновом стеке. Чтение исходного кода также не помогает прояснить ситуацию. Однако, судя по поведению, которое показывает ваше приложение, кажется, что он не пытается запустить upIntent
активность.
Независимо от того, какая реализация правильная или неправильная, конечным результатом является то, что вы хотите поведение FLAG_ACTIVITY_CLEAR_TOP
, а не поведение native API 16. К сожалению, это означает, что вам придется дублировать аппроксимацию библиотеки поддержки.
Что правильно?
Отказ от ответственности: я не работаю для Google, так что это мое лучшее предположение.
Я предполагаю, что поведение API 16+ - это предполагаемое поведение; это встроенная реализация, которая имеет доступ к внутренним компонентам Android и может делать то, что невозможно с помощью API. Pre-API 16, я не думаю, что можно было разматывать заднюю часть таким способом, кроме как с использованием флагов намерения. Таким образом, флаг FLAG_ACTIVITY_CLEAR_TOP
является ближайшим приближением поведения API 16, доступным для платформ pre-API 16.
К сожалению, результат заключается в том, что между встроенной реализацией и реализацией библиотеки поддержки существует нарушение принципа наименьшего удивления в вашем сценарии. Это заставляет меня задаться вопросом, является ли это непредвиденным использованием API. Я уверен, что Android ожидает, что вы пройдете полный путь навигации к активности, а не сразу перейдете к нему.
Только в случае
Чтобы избежать одного из возможных заблуждений, возможно, что кто-то может ожидать, что shouldUpRecreateTask
волшебным образом определит, что родительский элемент не находится в фоновом стеке и проходит процесс синтеза всего для вас с помощью TaskStackBuilder
.
Однако shouldUpRecreateTask
в основном определяет, была ли ваша активность запущена непосредственно вашим приложением (в этом случае она возвращает false
), или если она была запущена из другого приложения (в этом случае она возвращает true
). Из этой книги библиотека поддержки проверяет, не является ли намерение "действие" не ACTION_MAIN
(я этого не совсем понимаю), тогда как на платформах API 16 он выполняет эта проверка основана на близости задачи. Тем не менее, в случае этого приложения, все работает до shouldUpRecreateTask
, возвращающего false.