Приложение перезапускает, а не возобновляет

Надеюсь, кто-то может помочь мне понять, если не решение, по крайней мере, объяснение поведения.

Проблема:

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

Деталь:

Когда вы нажимаете «Значок запуска», приложение запускается нормально. То есть я предполагаю, что Intent запускается с именем вашего первого Activity с действием android.intent.action.MAIN и категорией android.intent.category.LAUNCHER , Однако это не всегда так:

На большинстве устройств, если вы нажмете значок запуска после того, как приложение уже запущено, текущее запущенное действие в этом процессе возобновляется ( НЕ начальное действие). Он возобновляется так же, как если бы вы выбрали его из «Недавних задач» в меню ОС. Это поведение, которое я хочу на всех устройствах.

Однако на выбранных других устройствах происходит различное поведение:

  • На Motorola Xoom, когда вы нажимаете значок запуска, приложение всегда запускает начальный запуск Activity независимо от того, что в данный момент выполняется. Я предполагаю, что значки запуска всегда запускают намерение «LAUNCHER».

  • На вкладке Samsung 2, когда вы нажимаете значок запуска, если вы только что установили приложение, он всегда будет запускать начальную Activity (то же, что и Xoom), однако после перезапуска устройства после установки значок запуска будет Вместо этого возобновите приложение. Я полагаю, что эти устройства добавляют «установленные приложения» в таблицу поиска при запуске устройства, которые позволяют значкам запуска запускать правильно запускаемые задачи?

Я прочитал много ответов, которые похожи на мою проблему, но просто добавление android:alwaysRetainTaskState="true" или использование launchMode="singleTop" для Activity – это не ответ.

Редактировать:

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

Solutions Collecting From Web of "Приложение перезапускает, а не возобновляет"

Поведение, которое вы испытываете, вызвано проблемой, которая существует в некоторых пусковых установках Android начиная с API 1. Здесь вы найдете подробную информацию об ошибке, а также о возможных решениях: https://code.google.com/p/android/issues/ Detail? Id = 2373 .

Это относительно распространенная проблема на устройствах Samsung, а также на других производителях, которые используют пользовательский пусковой механизм / кожу. Я не видел, чтобы проблема возникала на пусковой установке Android.

В основном приложение фактически не перезагружается полностью, но ваша стартовая активность запускается и добавляется в верхнюю часть стека активности, когда приложение возобновляется при запуске. Вы можете подтвердить это, нажав кнопку «Назад», когда вы возобновите приложение, и вы увидите начальную активность. Затем вы должны быть представлены в действие, которое, как вы ожидали, будет показано при возобновлении приложения.

Обходной путь, который я решил реализовать для решения этой проблемы, – проверить действие Intent.CATEGORY_LAUNCHER и Intent.ACTION_MAIN в намерении, которое запускает начальную активность. Если эти два флага присутствуют, а Activity не находится в корне задачи (это означает, что приложение уже запущено), я вызываю finish () в начальной операции. Это точное решение может не сработать для вас, но что-то подобное должно.

Вот что я делаю в onCreate () начального / запуска Activity:

  if (!isTaskRoot() && getIntent().hasCategory(Intent.CATEGORY_LAUNCHER) && getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN)) { finish(); return; } 

Этот вопрос по-прежнему актуальен в 2016 году. Сегодня тестером QA было сообщено о перезагрузке приложения, а не возобновлении с пусковой установки в Android M.

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

  1. Загрузить из игрового магазина (или sideload apk)
  2. Запустить приложение из диалогового окна магазина воспроизведения: отображается действие A [стек задач: A]
  3. Перейдите к активности B [стек задачи: A -> B]
  4. Нажмите кнопку «Главная»
  5. Запустите приложение из ящика приложений: появится действие A! [Task stack: A -> B -> A] (пользователь может нажать кнопку «Назад», чтобы перейти к активности «B»)

Примечание. Эта проблема не проявляется для отладки APK, развернутой через ADB, только в APK, загруженных из Play Store или загруженных боковыми. В последнем случае цель запуска с шага 5 содержала флаг Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT , но не в случаях отладки. Проблема исчезнет после того, как приложение было запущено с пусковой установки. Мое подозрение заключается в том, что Задача высевается с неправильным (точнее, нестандартным) намерением, которое предотвращает правильное поведение запуска до тех пор, пока задача не будет полностью очищена.

Я пробовал различные режимы запуска активности , но эти настройки слишком сильно отклоняются от стандартного поведения, которое должен ожидать пользователь: возобновление задачи в действии B. См. Следующее определение ожидаемого поведения в руководстве к задачам и обратному стеку в нижней части страницы В разделе «Запуск задачи»:

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

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

  /** * Ensure the application resumes whatever task the user was performing the last time * they opened the app from the launcher. It would be preferable to configure this * behavior in AndroidMananifest.xml activity settings, but those settings cause drastic * undesirable changes to the way the app opens: singleTask closes ALL other activities * in the task every time and alwaysRetainTaskState doesn't cover this case, incredibly. * * The problem happens when the user first installs and opens the app from * the play store or sideloaded apk (not via ADB). On this first run, if the user opens * activity B from activity A, presses 'home' and then navigates back to the app via the * launcher, they'd expect to see activity B. Instead they're shown activity A. * * The best solution is to close this activity if it isn't the task root. * */ if (!isTaskRoot()) { finish(); return; } 

UPDATE: отмените это решение от флажков разбора синтаксического анализа до запроса, если действие находится непосредственно в основе задачи. Флаги Intent трудно предсказать и протестировать со всеми различными способами открытия MAIN-активности (запуск из дома, запуск с кнопки «вверх», запуск из Play Маркета и т. Д.),

Ага! (Tldr; см. Инструкции, выделенные полужирным шрифтом внизу)

Я нашел проблему … Думаю.

Итак, я начну с предположения. Когда вы нажимаете кнопку запуска, она либо запускает действие по умолчанию, либо, если Task запущенная предыдущим запуском, открыта, она выводит ее на передний план. Положите другой путь. Если на любом этапе вашей навигации вы создаете новую Task и finish старую, запускающая программа теперь больше не будет возобновлять ваше приложение.

Если это предположение верно, я уверен, что это должно быть ошибкой, учитывая, что каждая Task находится в одном и том же процессе и является столь же действительной кандидатом на резюме, как и первый из них?

Моя проблема тогда была устранена путем удаления этих флагов из нескольких Intents :

 i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK ); 

Хотя совершенно очевидно, что FLAG_ACTIVITY_NEW_TASK создает новую Task , я не понимаю, что это предположение было действительно. Я считал это виновником и удалял его для тестирования, и у меня все еще была проблема, поэтому я отклонил его. Однако у меня все еще были следующие условия:

 i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) 

Мой экран заставки запускал «основное» действие в моем приложении, используя флаг выше. Afterall, Если бы у меня было «перезапустить» мое приложение, и Activity все еще работала, я бы скорее сохранил его информацию о состоянии.

Вы заметите, что в документации не упоминается о запуске новой Task :

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

Например, рассмотрите задачу, состоящую из действий: A, B, C, D. Если D вызывает startActivity () с намерением, который разрешает компонент активности B, то C и D будут завершены, а B получит заданное намерение , В результате чего стек теперь составляет: A, B.

Текущий исполняемый экземпляр действия B в приведенном выше примере либо получит новое намерение, которое вы начинаете здесь, в его методе onNewIntent (), либо сам закончите и перезапустите с новым намерением. Если он объявил свой режим запуска «множественным» (по умолчанию), и вы не установили FLAG_ACTIVITY_SINGLE_TOP в том же намерении, то он будет завершен и заново создан; Для всех других режимов запуска или если установлен FLAG_ACTIVITY_SINGLE_TOP, этот Intent будет доставляться в onNewIntent () текущего экземпляра.

Этот режим запуска также может быть использован для хорошего эффекта в сочетании с FLAG_ACTIVITY_NEW_TASK: если он используется для запуска корневой активности задачи, он приведет к запуску текущего исполняемого экземпляра этой задачи на передний план, а затем очистит его до корневого состояния. Это особенно полезно, например, при запуске деятельности из диспетчера уведомлений.

Итак, у меня была ситуация, описанная ниже:

  • Запущен B с FLAG_ACTIVITY_CLEAR_TOP , A заканчивается.
  • B хочет перезапустить службу, поэтому отправляет пользователя в A которого есть логика перезапуска службы и пользовательский интерфейс (без флагов).
  • A запускает B с FLAG_ACTIVITY_CLEAR_TOP, A заканчивается.

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

Итак, если все мое предположение верно:

  • Launcher только возобновляет первоначально созданную задачу
  • FLAG_ACTIVITY_CLEAR_TOP будет, если он перезапустит единственное оставшееся действие, также воссоздает новую Task

У меня была такая же проблема на устройствах Samsung. После многого поиска ни один из этих ответов не работал для меня. Я обнаружил, что в файле AndroidManifest.xml для launchMode установлено значение singleInstance ( android:launchMode="singleInstance" ). Удаление атрибута launchMode исправило мою проблему.

То, что я нашел в моем случае, состоит в том, что, когда у вас есть активность заставки, которая запускается каждый раз, например, активность splash_screen (launch_mode = normal) -> MainActivity (launch_mode = single instance), тогда у вас есть эта проблема с запуском приложения С экрана заставки каждый раз, даже если приложение работает. Удаление «единственного экземпляра» из MainActivity решило проблему для меня. Хотя я хотел, чтобы один экземпляр …

Бесценный для ваших пользователей. Идеальное резюме даже после нескольких недель в списке недавно использованных приложений.

Это похоже на резюме для пользователя, но на самом деле это полномасштабное начало.

Предыстория: память, используемая приложениями, которые находятся в основной деятельности, которые не запускали задачу, легко восстановить. ОС может просто перезапустить приложение с исходным пакетом, переданным onCreate. Однако вы можете добавить исходный пакет в onSaveInstanceState поэтому, когда ваше приложение перезагружается операционной системой, вы можете восстановить состояние экземпляра, и никто не станет более мудрым относительно того, возобновлено или возобновлено приложение. Возьмем, к примеру, программу классической карты. Пользователь перемещается в позицию на карте и затем нажимает домашний ключ. Через две недели это приложение сопоставления по-прежнему находится в списке последних приложений, а также facebook, pandora и candy crush. ОС не просто сохраняет имя приложения для недавно использованных приложений, но и сохраняет исходный пакет, используемый для запуска приложения. Однако программист закодировал метод onSaveInstanceState поэтому теперь пакет orignal содержит все материалы и информацию, необходимые для создания приложения, поэтому похоже, что он был возобновлен.

Пример. Сохраните текущую позицию камеры в onSaveInstanceState просто, если приложение выгружено и должно быть перезапущено через несколько недель из списка последних приложений.

 @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); // save the current camera position; if (mMap != null) { savedInstanceState.putParcelable(CAMERA_POSITION, mMap.getCameraPosition()); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // get the exact camera position if the app was unloaded. if (savedInstanceState != null) { // get the current camera position; currentCameraPosition = savedInstanceState .getParcelable(CAMERA_POSITION); } 

Примечание: вы также можете использовать метод onRestoreInstanceState но мне легче восстановить экземпляр в onCreate .

Это более чем вероятно, что происходит в вашем приложении. На некоторых устройствах ваше приложение выгружается в свободную память. Да, есть флаги, которые помогают, но флаги не будут подбирать каждый нюанс вашего приложения, и флаги не будут держать вас в живых в течение нескольких недель, как onSaveInstanceState . Вы должны закодировать идеальные две недели спустя возобновить. Это непростая задача для сложного приложения, но мы позади вас и здесь, чтобы помочь.

Удачи