Почему активность пусковой установки с launchMode = singleTask всегда перемещается на вершину backstack, даже если другая активность была на вершине?

В моем действии программы запуска для атрибута launchMode установлено значение singleTask из-за определенных требований.

<activity
    android:name=".map.MapsActivity"
    android:launchMode="singleTask"
    android:screenOrientation="portrait"
    android:theme="@style/MapScreenTheme"
    android:windowSoftInputMode="adjustPan">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

Проблема, с которой я столкнулся, заключается в том, что если я открою другое действие -> нажмите кнопку домой -> щелкните значок приложения в приложении запуска -> Он откроет MapActivity, а не действие, которое было открыто ранее.

Однако этого не происходит, если я перехожу к приложению через меню последних. Тогда вновь открытая активность остается наверху.

Может кто-нибудь объяснить, что здесь происходит в отношении backstack и почему ActivityManagerService не принимает во внимание, что процесс приложения уже существует, и все же решает запустить приложение запуска и очистить backstack, а не просто продвинуть приложение вперед?

Эту проблему можно наблюдать в небольшом примере приложения, созданном здесь - https://github.com/abhiank/SingleTaskActivity


person vepzfe    schedule 09.04.2020    source источник
comment
Вы пробовали какое-либо решение из этого потока .. ?   -  person ADM    schedule 17.04.2020
comment
@ADM. Большое спасибо. Я не могу поверить, что не нашел эту ветку, несмотря на все поиски. Итак, в конечном итоге решение состоит в том, чтобы иметь вспомогательное действие, которое запускает основное действие, поскольку singleTask просто убивает все остальные действия над ним.   -  person vepzfe    schedule 17.04.2020
comment
Да, это заставило меня подумать, что это очевидный вопрос, который нужно было задать раньше. Поэтому я немного покопался. Если у вас есть решение, добавьте ответ и примите его, чтобы закрыть Bounty.   -  person ADM    schedule 17.04.2020
comment
Ага. Думаю, мне следовало копнуть глубже. Что ж, это не совсем решение. Просто обходной путь. Я думаю, лучше всего было бы пометить эту цепочку как дублирующую и сослаться на нее.   -  person vepzfe    schedule 17.04.2020
comment
Вообще говоря, использование специального launchMode вызывает больше проблем, чем решает. Пожалуйста, объясните, почему вы считаете, что вам нужен этот специальный режим запуска.   -  person David Wasser    schedule 18.04.2020
comment
@DavidWasser Мне это нужно, чтобы несколько экземпляров этого действия не открывались. В этом упражнении я показываю карту с маршрутом. Параллельно у меня есть функция, в которой пользователь может поделиться ссылкой на приложение с картами Google. Чтобы проанализировать местоположение и название места из этой ссылки, я открываю новое действие для другой задачи (чтобы оно не складывалось поверх задачи действия карты). Если синтаксический анализ успешен, я открываю действие карты. Если я не упоминаю singleTask, то два экземпляра активности карты - один в исходном и один в ссылке на карты Google, откроются с одним и тем же загруженным маршрутом.   -  person vepzfe    schedule 18.04.2020
comment
Вы сможете решить эту проблему с помощью taskAffinity, и вам не потребуются специальные режимы запуска.   -  person David Wasser    schedule 18.04.2020
comment
@DavidWasser Я использую taskAffinity. Вот как действие по обмену URL-адресом не влияет на основной задний стек. Я бы также хотел использовать taskAffinity в основном backstack, но проблема в том, что я не могу установить настраиваемый taskAffinity в намерении открыть основное действие из действия url.   -  person vepzfe    schedule 18.04.2020
comment
@ADM, не могли бы вы отправить ссылку, которой вы поделились в качестве ответа. Я дам тебе награду. Я не могу пометить этот вопрос как повторяющийся, пока не будет объявлено открытое вознаграждение.   -  person vepzfe    schedule 18.04.2020
comment
пожалуйста, опубликуйте свой манифест. Я не думаю, что это правильно, и хотел бы сам воспроизвести такое поведение.   -  person David Wasser    schedule 19.04.2020
comment
Кроме того, я только что нашел свой очень подробный ответ на связанный с этим вопрос, хотя и не о поведении launchMode="singleTask". Взгляните на это: stackoverflow.com/a/29376250/769265 Использование повторного родительства задачи может быть для вас способом чтобы решить вашу проблему.   -  person David Wasser    schedule 19.04.2020
comment
@DavidWasser Я создал небольшое репо, чтобы продемонстрировать эту проблему здесь - github.com/abhiank/SingleTaskActivity   -  person vepzfe    schedule 19.04.2020
comment
@DavidWasser Спасибо за ссылку на ваш ответ о повторении задачи. Я никогда раньше не слышал и не использовал его. Это может решить мою задачу, удалив саму singleTask (хотя я еще не уверен), однако это не решит эту текущую проблему, поскольку оба действия находятся в одной задаче с одинаковым сродством задачи. Кроме того, спасибо за ваше объяснение различий между запуском из значка приложения и недавними. Было бы здорово, если бы вы могли подробнее остановиться на этом. Это то, что меня до сих пор недоумевает. Я тоже подумывал покопаться в исходном коде.   -  person vepzfe    schedule 19.04.2020


Ответы (4)


Я думаю, что это желаемое поведение SingleTask режима запуска. Сохранение активности Launcher как SingleTask имеет свои последствия.

Я не могу придумать точного решения этой проблемы, но какой-то обходной путь сделает работу.

Добавление ссылки ниже, которую я упомянул в комментарии, чтобы пройти.

Android: ошибка в launchMode = singleTask? - ›Стек активности не сохраняется

person ADM    schedule 18.04.2020
comment
Это не так. Желаемое поведение singleTask описано здесь: developer.android .com / guide / components / activity / Если вы посмотрите на рисунок 4, он даже явно показывает задачу, содержащую 2 действия, где корень Activity объявлен с помощью launchMode="singleTask" - person David Wasser; 19.04.2020
comment
Спасибо, @DavidWasser, я приму прочтение .. - person ADM; 19.04.2020
comment
На самом деле, я только что нашел свой очень подробный ответ на связанный вопрос, который охватывает большую часть этой темы (хотя и не конкретно о поведении launchMode="singleTask". Взгляните здесь: stackoverflow.com/a/29376250/769265 - person David Wasser; 19.04.2020

Я думаю, что когда вы снова щелкаете значок приложения, он открывает действие Launcher поверх ранее открытого Activity. Что вы можете сделать, так это применить простую проверку, есть ли какие-либо действия в backstack, кроме этого, а затем завершить это действие запуска, оно покажет ранее открытый экран. Попробуйте ссылку ниже. https://stackoverflow.com/a/38450232/3497972

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

Как сделать вернуться к последнему открытому действию при перезапуске приложения для Android?

приложение Android перезапускается при открытии нажатием на значок приложения

Определить, когда щелкают значок приложения для запуска приложение в android

В чем разница между запуском приложения из недавних приложений и нажатием на значок приложения

person akashzincle    schedule 12.04.2020
comment
Спасибо за Ваш ответ. Я попробовал ответить на этот вопрос в вашей ссылке. Однако onCreate никогда не вызывается, поскольку действие с singleTask, если оно находится в backstack. Я попытался поместить тот же код в onNewIntent (), и он был вызван, однако к тому времени isTaskRoot () уже был истинным. Это означает, что backstack уже был очищен, и это действие уже было помещено в начало до того, как был вызван onNewIntent. Еще раз спасибо за ссылку. У этого вопроса тоже была та же проблема, что и у меня. - person vepzfe; 17.04.2020
comment
@abhiank обновил ответ с большим количеством ссылок, в котором также есть другие подходы, может помочь вам, пройдите их - person akashzincle; 18.04.2020
comment
Еще раз спасибо за эти ссылки. Интересно читает. Однако ни один из них не пригодился. Большинство из них касалось проблем, связанных с открытием приложения с помощью кнопки открытия установщика и щелчка по значку запуска. Я надеялся, что по вашей последней ссылке будет проведена более глубокая работа над тем, что происходит по-другому, когда приложение возобновляется с последних, но, увы, в нем не было необходимой информации. - person vepzfe; 18.04.2020

Есть решение для случая, когда ваше основное действие будет запускаться только другими действиями в вашем собственном приложении:

Вы можете удалить атрибут launchMode из определения основного действия в манифесте. И просто передайте Intent.FLAG_ACTIVITY_NEW_TASK каждому намерению, которое открывает ваш MainActivity, например так:

Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

Имейте в виду, что поведение Intent.FLAG_ACTIVITY_NEW_TASK или launchMode="singleTask" в вашем собственном приложении работает только в сочетании с атрибутом taskAffinity в определении действия в манифесте.

Надеюсь, это вам немного поможет.

person Николай Гольцев    schedule 11.04.2020
comment
Спасибо за Ваш ответ. Но у меня это не работает. Я не могу контролировать намерение действия пусковой установки. Это контролируется приложением запуска и службой диспетчера действий. Кроме того, мне не нужно открывать активность в новой задаче. Меня устраивает, что основное действие открывается в задаче по умолчанию. Я только хочу понять, почему активность пусковой установки с одной задачей всегда перемещается на вершину бэкстека. - person vepzfe; 12.04.2020
comment
Intent.FLAG_ACTIVITY_NEW_TASK и launchMode = singleTask имеют идентичное поведение. Суть моего предложения - установить режим singleTask через флаг намерения, а не атрибут. Конечно, если ваше приложение будет использоваться другими приложениями (отправьте ему намерения), мое решение не будет работать для вас, в противном случае у вас будет полный контроль над намерениями в своей основной деятельности. Что касается намерения из приложения-лаунчера, нет необходимости его контролировать, при таком подходе он работает хорошо. - person Николай Гольцев; 12.04.2020
comment
Я понимаю. Однако проблема в том, что я не контролирую намерение, открывающее действие средства запуска. Действие программы запуска просто открывается службой диспетчера действий. - person vepzfe; 17.04.2020
comment
Я имею в виду, что если ваша основная деятельность служит помощником для других приложений. Предположим ситуацию: пользователь хочет отправить электронное письмо из какого-либо приложения, когда он это делает, система Android поддерживает это действие, и результатом этого будет некоторая активность (из текущего приложения или другого приложения, это не имеет значения, просто действие, которое может выполнить это задание), с помощью которого пользователь может выполнить свою задачу по отправке электронной почты. Теперь, если ваша основная деятельность - это не какая-то деятельность, описанная выше, мое решение работает хорошо, в противном случае, конечно, вы должны получить другое решение. - person Николай Гольцев; 17.04.2020
comment
Вы хотите сказать, что я использую обычное действие, которое является активностью программы запуска, и использую его для начала своей основной деятельности? - person vepzfe; 17.04.2020
comment
Я пытаюсь сказать, что если ваша пусковая установка будет запускаться ТОЛЬКО другими действиями вашего приложения ИЛИ с главного экрана, вы можете использовать мое решение, и оно хорошо работает в этом случае. - person Николай Гольцев; 17.04.2020
comment
Извините, но я до сих пор не понимаю, как именно установить flag = Intent.FLAG_ACTIVITY_NEW_TASK, если действие открывается с главного экрана. Эта часть контролируется ActivityManager, и я не могу установить там флаг! - person vepzfe; 17.04.2020
comment
Хорошо, я понял. Вам не нужно обрабатывать этот конкретный случай (изменить намерение с домашнего экрана), он хорошо работает, если вы просто оставите его как есть. - person Николай Гольцев; 17.04.2020
comment
Позвольте нам продолжить это обсуждение в чате. - person Николай Гольцев; 17.04.2020
comment
Ваше решение по-прежнему не работает. Я четко упомянул в вопросе, что проблема в HOME - ›A -› B - ›HOME, затем нажмите на значок приложения, чтобы открыть A, а не A-› B. Я никогда не упоминал, что A открывается из какой-либо другой деятельности. - person vepzfe; 17.04.2020

Мне кажется, вы видите эту неприятную давнюю ошибку в Android.

Повторный запуск Активность на кнопке "Домой", но ... только в первый раз

Чтобы проверить, так ли это, пожалуйста, закройте свое приложение (настройки-> приложения-> ваше приложение-> принудительный выход). Затем запустите приложение, нажав значок приложения на ГЛАВНОМ экране. Сделайте все, что вам нужно, чтобы запустить еще один Activity в задачу. Нажмите HOME. Теперь снова коснитесь значка на ГЛАВНОМ экране. Это должно вывести вашу задачу на передний план в том же состоянии, в котором вы ее оставили.

person David Wasser    schedule 18.04.2020
comment
Привет, @David, спасибо за ответ. Однако это не та ошибка, с которой я столкнулся. На самом деле ошибка заключается в следующем - stackoverflow.com/questions/2417468/ - person vepzfe; 18.04.2020
comment
Связанный вопрос описывает в основном ту же ошибку. На этот вопрос есть ответы, которые совершенно неверны, но если есть ошибка, это ошибка, которую я описал. Вы проверили это, выполнив то, что я предложил? - person David Wasser; 18.04.2020
comment
Я пробовал. Это не тот сценарий, который происходит. Это отдельные ошибки. В моем случае onCreate не вызывается для основного действия. Сначала вызывается onDestroy для Activity B, затем onDetachedFromWindow и, наконец, onNewIntent для mainActivity. А в newIntent isTaskRoot () всегда истинно. На самом деле, на данный момент я не думаю, что это можно назвать ошибкой. Похоже, что активность с singleTask ведет себя именно так. Единственное решение - наличие активности делегата. - person vepzfe; 18.04.2020