Завершите старую деятельность и начните новую или наоборот


80

Я знаю, что получаю одинаковый результат с обоими фрагментами кода

finish();
startActivity(newActivity);

и

startActivity(newActivity);
finish();

Хотелось бы узнать ваше мнение, если между ними есть большая разница. Одно лучше другого? Если да, то почему?

Ответы:


61

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


1
для меня это тоже звучит разумно
Тима

6
Анимация у меня другая. Смотрите мой ответ ниже.
Monstieur

но подход совершенно НЕПРАВИЛЬНЫЙ .. Существуют флаги (для намерения, а также в манифесте), которые действительно существуют для этих вариантов использования.
Ewoks

@Ewoks, пожалуйста, идите, что значит, какие флаги?
Энтони

3
На самом деле существует большая разница в поведении задач приложения. Я подробно остановился на этом вопросе.
Вит Худенко

27

Анимация явно другая (по крайней мере, на 4.1 и далее). При finish()первом вызове начинает исчезать первое действие раньше, и вы можете ненадолго увидеть черный фон, прежде чем исчезнет новое действие. При startActivity()первом вызове новое действие исчезает поверх старого, и черный фон не виден.


16

Существует важное различие в поведении задач приложения в зависимости от порядка startActivity()и finish()вызовов.

Случай, который я описываю, относится только к ситуации, когда текущее действие (то, которое останавливается) является единственным в задаче.

Обычно можно ожидать, что начальное намерение (созданное вами намерение начать другое действие) не изменяется системой. И это не тот случай, если finish()вызывается последнее действие в задаче перед вызовом startActivity().

В этом случае ActivityManager, системный компонент, при выполнении флага startActivity() добавляет Intent.FLAG_ACTIVITY_NEW_TASK к вашему намерению.

Когда это происходит, можно заметить запись журнала в LogCat, подобную этой:

W / ActivityManager: startActivity вызывается после завершения ActivityRecord {4a19b47 u0 com.foo.bar/com.foo.bar.SplashActivity t4928 f}; принудительное использование Intent.FLAG_ACTIVITY_NEW_TASK для: Intent {cmp = com.foo.bar / com.foo.bar.MainActivity}

И это поворотный момент, после которого (при определенных условиях) что-то может пойти не так.

Подводя итог, если вы хотите быть в безопасности (вместо того, чтобы испытывать неожиданные побочные эффекты от FLAG_ACTIVITY_NEW_TASKдобавления к намерению), то порядок должен быть следующим:

  • startActivity()
  • finish()

Демо- проект .

Записи с экрана:


Глядя на исходный код, Activity.startActivity () в конечном итоге вызывает ActivityThread.sendActivityResult (), который, в свою очередь, вызывает scheduleSendResult (), который просто добавляет действие в очередь. Поток обработает его позже. С другой стороны, finish () вызывает ActivityManagerNative.finishActivity (), который сразу же завершает действие.
Эммануэль

@Emmanuel, я не могу понять, относится ли ваше заявление к описанной мною проблеме. :)
Вит Худенко

9

В дополнение к ответу Эммануэля:

Оба метода startActivityи finishбудут запланированы после завершения вызывающего метода, поскольку оба обрабатываются потоком пользовательского интерфейса.


7

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

Если бы вы сделали наоборот, возможно, у намерения не было времени сработать до того, как очистка будет завершена. Т.е. будет ли операция вызывать startActivity () после вызова finish ()?

Надеюсь, вы понимаете, о чем я пытаюсь заявить, я бы выбрал второй вариант на всякий случай.


Да, я понял вашу идею. Звучит логично. Но я не могу представить себя, когда такая ситуация могла бы быть возможна
Тима

2

У меня была аналогичная проблема:

Activity A: singleInstance
Activity B: singleInstance
Activity C: singleInstance

A starts B 
B starts C
C wants to start A:

здесь, если я использую:

finish();
startActivity(A);

происходит нечто связное: на передний план выходит действие B вместо A! но если я изменю код следующим образом:

startActivity(A);
finish();

все в порядке, и действие А становится видимым.

Я не знаю, в чем проблема, но кажется, что в первом случае C завершает работу до выполнения команды startActivity, так что задний стек обрабатывает ситуацию и показывает свою главную активность, которая является B! но во втором случае все происходит нормально.


Когда вы finish () приложение, android извлекает активность LRU из стека, которая равна B. Кроме того, я думаю, что finish () выполняется немедленно, а не асинхронно.
Mehmet AVŞAR

0

Я обычно делаю это startActivity()раньше, finish()поскольку думаю, что это обеспечит появление нового экрана до того, как погаснет предыдущий.

В моем приложении есть страница входа. После успешного входа пользователя активность входа прекращается, а основная активность продолжается. Он отлично работает в Android 4.

Сегодня я хотел переписать его в материальном дизайне. Однако у меня возникла большая проблема. Новая студия Android создает пустую активность с материальным дизайном, что, как мне кажется, требует много ресурсов. Тот же процесс, но я получил ошибку

11-26 18:20:44.450 18397-18397/? I/Choreographer: Skipped 42 frames!  The application may be doing too much work on its main thread.
11-26 18:20:44.485 18397-18408/? I/art: Background partial concurrent mark sweep GC freed 2864(191KB) AllocSpace objects, 4(43MB) LOS objects, 13% free, 100MB/116MB, paused 8.056ms total 39.767ms

Он сказал, что мои приложения mainActivityтребуют много ресурсов при запуске в моем телефонном журнале. У меня нет ничего, кроме mainActivityтого, что это макет Material Design по умолчанию.

Я поменял порядок, и теперь он работает без ошибок на моем телефоне.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.