Режим запуска Android "Single Top" и метод onNewIntent - PullRequest
43 голосов
/ 11 ноября 2009

Я прочитал в документации по Android, что, установив для свойства ActivityModem Activity значение singleTop ИЛИ, добавив флаг FLAG_ACTIVITY_SINGLE_TOP к моему Intent, вызов startActivity(intent) будет повторно использовать один экземпляр Activity и даст мне Intent в onNewIntent Перезвоните. Я сделал обе эти вещи, и onNewIntent никогда не стреляет, а onCreate стреляет каждый раз. В документах также говорится, что this.getIntent() возвращает намерение, которое было впервые передано действию, когда оно было впервые создано. В onCreate я звоню getIntent и каждый раз получаю новый (я создаю объект намерения в другом действии и добавляю к нему дополнительный ... этот дополнительный должен быть одинаковым каждый раз, если это возвращало мне тот же объект намерения). Все это заставляет меня поверить, что моя деятельность не ведет себя как «единственная вершина», и я не понимаю, почему.

Чтобы добавить некоторый фон в случае, если я просто пропускаю необходимый шаг, вот мое объявление 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);

Ответы [ 3 ]

36 голосов
/ 11 ноября 2009

Вы проверяли, был ли вызван onDestroy()? Вероятно, поэтому onCreate() вызывается каждый раз вместо onNewIntent(), который вызывается только в том случае, если действие уже существует.

Например, если вы оставите свою деятельность с помощью кнопки BACK, она будет уничтожена по умолчанию. Но если вы поднимитесь выше в стеке действий к другим действиям и оттуда снова вызовете свой ArtistActivity.class, он пропустит onCreate() и сразу перейдет к onNewIntent(), потому что действие уже создано, и поскольку вы определили его как singleTop Android не будет создавать новый экземпляр этого, но возьмите тот, который уже валяется.

Что я делаю, чтобы увидеть, что происходит, я реализую фиктивные функции для всех различных состояний каждого действия, так что я всегда теперь понимаю, что происходит:

@Override
public void onDestroy() {
    Log.i(TAG, "onDestroy()");
    super.onDestroy();
}

То же самое для onRestart(), onStart(), onResume(), onPause(), onDestroy()

Если вышеупомянутое (кнопка BACK) не было вашей проблемой, реализация этих макетов, по крайней мере, поможет вам отладить их немного лучше.

26 голосов
/ 19 сентября 2015

Принятый ответ не совсем корректен. Если onDestroy () вызывался ранее, то да, onCreate () всегда вызывался бы. Однако это утверждение неверно : «Если вы поднимитесь выше в стеке действий к другим действиям и оттуда снова вызовите свой ArtistActivity.class, он пропустит onCreate () и перейдет непосредственно к onNewIntent ()» *

Раздел "singleTop" http://developer.android.com/guide/components/tasks-and-back-stack.html ясно объясняет, как это работает (внимание к полужирному тексту ниже; я также доказал это с помощью собственной отладки):

"Например, предположим, что задний стек задачи состоит из корневого действия A с действиями B, C и D сверху ( стек ABCD; D сверху ). Намерение приходит для активность типа D. Если в D по умолчанию установлен «стандартный» режим запуска, запускается новый экземпляр класса, и стек становится ABCDD. Однако, если режим запуска D - «singleTop», существующий экземпляр D получает намерение через onNewIntent (), потому что он находится на вершине стека - стек остается ABCD. Однако, , если приходит намерение для действия типа B, тогда новый экземпляр B добавляется в стек, даже если его запуск режим "singleTop". "

Другими словами, запуск действия через SINGLE_TOP будет повторно использовать существующее действие, только если оно уже находится на вершине стека . Это не будет работать, если другое действие в той же задаче находится наверху (например, действие, которое выполняет startActivity (SINGLE_TOP)); вместо этого будет создан новый экземпляр.

Вот два способа исправить это , чтобы получить желаемое поведение SINGLE_TOP, основная цель которого - повторно использовать существующее действие вместо создания нового ...

Первый способ (как описано в разделе комментариев принятых ответ): Вы можете добавить режим запуска «singleTask» в свою активность. Это вызовет onNewIntent (), потому что singleTask означает, что в данной задаче может быть только ОДИН экземпляр конкретного действия. Это несколько хакерское решение, потому что, если вашему приложению требуется несколько экземпляров этого действия в конкретной ситуации (как я это делаю для своего проекта), вы облажались.

Второй способ (лучше): Вместо FLAG_ACTIVITY_SINGLE_TOP используйте FLAG_ACTIVITY_REORDER_TO_FRONT. Это позволит повторно использовать существующий экземпляр действия, переместив его на вершину стека (onNewIntent () будет вызываться, как и ожидалось).

Основная цель FLAG_ACTIVITY_SINGLE_TOP - предотвратить создание нескольких экземпляров Activity. Например, когда эта деятельность может быть запущена через намерение, которое приходит извне основной задачи вашего приложения. Для внутреннего переключения между действиями в моем приложении я обнаружил, что вместо этого обычно используется FLAG_ACTIVITY_REORDER_TO_FRONT.

3 голосов
/ 25 августа 2016

Установите этот флаг на ваше намерение:

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP)
...