Режим запуска Android "single top" и метод onNewIntent
Я прочитал в документации Android, что, установив для свойства launchMode моей активности значение singleTop ИЛИ добавив FLAG_ACTIVITY_SINGLE_TOP
флаг к моему намерению, этот вызов startActivity(intent)
повторно использует один экземпляр Activity и выдает мне намерение в onNewIntent
обратном вызове. Я сделал обе эти вещи, и onNewIntent
никогда не срабатывает и onCreate
срабатывает каждый раз. В документах также говорится, что this.getIntent()
возвращает намерение, которое было впервые передано Activity при его первом создании. В onCreate
я вызываю getIntent
и каждый раз получаю новый (я создаю объект intent в другом действии и добавляю к нему дополнительный ... этот дополнительный должен быть одинаковым каждый раз, если он возвращает мне один и тот же объект intent). Все это наводит меня на мысль, что моя активность не работает как "single top", и я не понимаю почему.
Чтобы добавить немного информации на случай, если я просто пропустил необходимый шаг, вот мое объявление Activity в манифесте и код, который я использую для запуска activity. Само Activity не делает ничего, что стоило бы упомянуть в связи с этим:
в AndroidManifest.xml:
<activity
android:name=".ArtistActivity"
android:label="Artist"
android:launchMode="singleTop">
</activity>
в моей вызывающей активности:
Intent i = new Intent();
i.putExtra(EXTRA_KEY_ARTIST, id);
i.setClass(this, ArtistActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i);
Переведено автоматически
Ответ 1
Вы проверяли, вызывался ли onDestroy()
также? Вероятно, поэтому onCreate()
вызывается каждый раз вместо onNewIntent()
, который вызывался бы только в том случае, если activity уже существует.
Например, если вы завершаете свою активность с помощью кнопки "Назад", она по умолчанию уничтожается. Но если вы подниметесь выше по стеку действий в другие действия и оттуда вызовете свой ArtistActivity.class
снова, он пропустит onCreate()
и перейдет непосредственно к onNewIntent()
, потому что действие уже создано, и поскольку вы определили его как singleTop
Android не создаст его новый экземпляр, а возьмет тот, который уже лежит где-то поблизости.
Что я делаю, чтобы увидеть, что происходит, я реализую фиктивные функции для всех различных состояний каждого действия, поэтому я всегда знаю, что происходит:
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy()");
super.onDestroy();
}
То же самое для onRestart()
, onStart()
, onResume()
, onPause()
, onDestroy()
Если описанное выше (кнопка "Назад") не было вашей проблемой, реализация этих макетов, по крайней мере, поможет вам немного улучшить отладку.
Ответ 2
Принятый ответ не совсем корректен. Если onDestroy() был вызван ранее, то да, onCreate() будет вызываться всегда. Однако, это утверждение неверно: "Если вы подниметесь выше по стеку действий в другие действия и оттуда снова вызовете свой ArtistActivity.class он пропустит onCreate() и перейдет непосредственно к onNewIntent ()"
Раздел "singleTop" в http://developer.android.com/guide/components/tasks-and-back-stack.html просто объясняет, как это работает (обратите внимание на выделенный жирным шрифтом текст ниже; я также доказал это с помощью моей собственной отладки):
"Например, предположим, что задний стек задачи состоит из корневого действия A с действиями B, C и D сверху (стек A-B-C-D; D находится сверху). Появляется намерение для действия типа D. Если D имеет "стандартный" режим запуска по умолчанию, запускается новый экземпляр класса, и стек становится A-B-C-D-D. Однако, если режим запуска D - "singleTop", существующий экземпляр D получает intent через onNewIntent(), потому что он находится на вершине стека — стек остается A-B-C-D. Однако, если поступает намерение для действия типа B, то в стек добавляется новый экземпляр B, даже если его режим запуска "singleTop"."
Другими словами, запуск действия через SINGLE_TOP приведет к повторному использованию существующего действия только в том случае, если оно уже находится на вершине стека. Это не сработает, если другое действие в той же задаче находится наверху (например, действие, выполняющее startActivity(SINGLE_TOP)); вместо этого будет создан новый экземпляр.
Вот два способа исправить это, чтобы вы получили желаемое поведение SINGLE_TOP, общей целью которого является повторное использование существующего действия вместо создания нового...
Первый способ (как описано в разделе комментариев к принятому ответу): вы могли бы добавить режим запуска "singleTask" к вашей активности. Это приведет к принудительному использованию onNewIntent(), потому что singleTask означает, что в данной задаче может быть только ОДИН экземпляр определенного действия. Это несколько хакерское решение, потому что, если вашему приложению требуется несколько экземпляров этого действия в конкретной ситуации (как я делаю для своего проекта), вы облажались.
Второй способ (лучше): вместо FLAG_ACTIVITY_SINGLE_TOP используйте FLAG_ACTIVITY_REORDER_TO_FRONT . Это позволит повторно использовать существующий экземпляр activity, переместив его на вершину стека (onNewIntent() будет вызван, как и ожидалось).
Основная цель FLAG_ACTIVITY_SINGLE_TOP - предотвратить создание нескольких экземпляров Activity . Например, когда это действие может быть запущено с помощью намерения, которое исходит из-за пределов основной задачи вашего приложения. Для внутреннего переключения между действиями в моем приложении я обнаружил, что FLAG_ACTIVITY_REORDER_TO_FRONT - это, как правило, то, что я хочу вместо этого.
Ответ 3
Установите этот флаг в соответствии с вашими намерениями:
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP)