Какая конфигурация мне нужна, чтобы Android 11 не убивал мою активность SingleInstance после сворачивания моей основной задачи?

Мой текущий поток следующий:

  1. Пользователь входит в основное действие A
  2. Затем пользователь запускает действие B, которое является единственным экземпляром.
  3. Затем действие B запускает службу переднего плана.

Метод, который запускает службу переднего плана

public static void startService(Activity activity) {
    Intent serviceIntent = SomeService.newIntent(activity);
    ContextCompat.startForegroundService(activity, serviceIntent);
}

Сервис onStartCommand

Notification notification = getNotification();

startForeground(1, notification);

return START_NOT_STICKY;

Манифест

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
...
<activity
    android:name="com.proj.activities.ActivityA"
    android:screenOrientation="portrait" />
...
<activity
    android:name="com.proj.activities.ServiceActivityB"
    android:launchMode="singleInstance"
    android:screenOrientation="portrait" />
...
<service
    android:name="com.proj.SomeService"
    android:foregroundServiceType="location" />

Следующие действия поддерживают мой единственный экземпляр в Android 11 и предыдущей версии.

  1. Если активность B сведена к минимуму, служба переднего плана остается активной.
  2. Если пользователь запускает действие A из действия B (singleInstance), служба переднего плана остается активной.

Действие A запускает B:

Intent activityBIntent = new Intent(activity, ServiceActivityB.class);
activity.startActivity(activityBIntent);

Журналы:

* Task{328c3ce #30946 visible=true type=standard mode=fullscreen translucent=false A=10480:com.company.name U=0 StackId=30946 sz=1}
    mLastOrientationSource=ActivityRecord{b2900c9 u0 com.company.name/com.proj.activities.ServiceActivityB t30946}
    bounds=[0,0][1080,2280]
    * ActivityRecord{b2900c9 u0 com.company.name/com.proj.activities.ServiceActivityB t30946}
* Task{de6d50d #30945 visible=true type=standard mode=fullscreen translucent=false A=10480:com.company.name U=0 StackId=30945 sz=2}
    mLastOrientationSource=ActivityRecord{58892bb u0 com.company.name/com.proj.activities.SpringboardActivity 30945}
    bounds=[0,0][1080,2280]
    * ActivityRecord{58892bb u0 com.company.name/com.proj.activities.ActivityA t30945}
    * ActivityRecord{183c336 u0 com.company.name/com.proj.activities.SpringboardActivity t30945}

Актив Б запускает А:

Intent activityAIntent = new Intent(activity, ActivityA.class);
activityAIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
activity.startActivity(activityAIntent);

Журналы:

* Task{de6d50d #30945 visible=true type=standard mode=fullscreen translucent=false A=10480:com.company.name U=0 StackId=30945 sz=2}
  mLastOrientationSource=ActivityRecord{58892bb u0 com.company.name/com.proj.activities.SpringboardActivity t30945}
  bounds=[0,0][1080,2280]
    * ActivityRecord{58892bb u0 com.company.name/com.proj.activities.ActivityA t30945}
    * ActivityRecord{183c336 u0 com.company.name/com.proj.activities.SpringboardActivity t30945}
* Task{328c3ce #30946 visible=true type=standard mode=fullscreen translucent=false A=10480:com.company.name U=0 StackId=30946 sz=1}
mLastOrientationSource=ActivityRecord{b2900c9 u0 com.company.name/com.proj.activities.ServiceActivityB t30946}
bounds=[0,0][1080,2280]
    * ActivityRecord{b2900c9 u0 com.company.name/com.proj.activities.ServiceActivityB t30946

Но в Android 11, в отличие от предыдущих версий Android, если пользователь запускает действие A из действия B (singleInstance), а затем сворачивает приложение, OnDestroy() вызывается для действия B, которое содержит работающую службу.


person Sergio Adrian Nunez    schedule 16.12.2020    source источник
comment
если пользователь возвращается к действию A, а затем сворачивает приложение, OnDestroy() вызывается для действия B — это стандартное поведение для обратной навигации (уничтожает действие, которое было на переднем плане, и возвращает управление предыдущему действию на задний стек). Так было с Android 1.0. действие B, которое содержит работающую службу — startForegroundService() не связывает службу с конкретным действием, а startForegroundService() не препятствует работе обратной навигации.   -  person CommonsWare    schedule 17.12.2020
comment
@CommonsWare Я внес изменения в свой пост, чтобы уточнить, что я не использую обратную навигацию как таковую, а начинаю новую активность, возвращаясь к исходной. Еще одна вещь, которую я хочу уточнить, заключается в том, что действие B — это отдельный экземпляр, поэтому оно принадлежит отдельной задаче, отличной от действия A.   -  person Sergio Adrian Nunez    schedule 17.12.2020
comment
@ Адриан, вы пытались запустить службу как связанную службу из действия B, а затем переместить ее на передний план после уничтожения действия B?   -  person ginga_ninja217    schedule 17.12.2020
comment
Пожалуйста, отредактируйте свой вопрос и опубликуйте содержимое вашего манифеста. По крайней мере, объявления для 2 видов деятельности и службы.   -  person David Wasser    schedule 22.12.2020
comment
Как ActivityA запускает ActivityB и наоборот?   -  person David Wasser    schedule 22.12.2020
comment
@DavidWasser Я отредактировал свой пост с учетом ваших предложений, спасибо!   -  person Sergio Adrian Nunez    schedule 03.01.2021
comment
Здесь есть ряд вопросов, которые, безусловно, сбивают с толку. Вы объявили ActivityB с launchMode=:"singleInstance", но не указали taskAffinity. Это означает, что когда ActivityA запускает ActivityB, режим запуска игнорируется и ActivityB запускается в той же задаче, что и ActivityA. Это может быть или не быть тем, что вы хотели. Вы можете проверить это, запустив ActivityB из ActivityA, а затем используя adb shell dumpsys activity activities, и вы должны увидеть только 1 задачу для своего приложения (а не 2).   -  person David Wasser    schedule 03.01.2021
comment
Итак, теперь у вас есть задача с ActivityA в качестве root и ActivityB поверх нее. Когда ActivityB теперь запускает ActivityA с помощью флагов CLEAR_TOP и SINGLE_TOP, ActivityB удаляется из задачи (завершается), и пользователь возвращается к исходному экземпляру ActivityA. Вы также должны увидеть это с помощью adb shell dumpsys activity activities. Поскольку ActivityB закончен, в какой-то момент на нем будет вызван onDestroy(). Это также должно быть поведение до Android 11.   -  person David Wasser    schedule 03.01.2021
comment
Чтобы помочь вам, проверьте свой код как на Android 11, так и на более ранней версии Android, и с помощью команд adb shell определите, есть ли у вас 1 задача или 2. Я не понимаю, как у вас может быть 2 задачи, поскольку taskAffinity переопределяет launchMode, и оба действия имеют одинаковое значение. (по умолчанию) taskAffinity. Пожалуйста, сообщите нам о своих выводах (вы можете отредактировать свой вопрос и добавить соответствующую информацию), и тогда я смогу внести другие предложения.   -  person David Wasser    schedule 03.01.2021
comment
Похоже, что в Android 11 есть некоторые изменения в поведении taskAffinity. Я не проверял это сам, но я уже ответил на этот вопрос, который похож на ваш: stackoverflow.com/questions/64769530/ Мне нужно провести еще несколько исследований, чтобы действительно понять, что изменилось .   -  person David Wasser    schedule 03.01.2021
comment
@DavidWasser Я обновил свой вопрос, чтобы показать журналы Android 11. Я проверил действия, и было создано две задачи с одним и тем же taskAffinity. Я также обнаружил, что в Android 11, когда у вас есть более одной задачи с одинаковым сходством, после того, как я сворачиваю свое приложение, наименее используемая задача уничтожается, это поведение вызывает мою проблему.   -  person Sergio Adrian Nunez    schedule 07.01.2021
comment
Опубликуйте запись манифеста для SpringBoardActivity, которая является корнем Activity задачи.   -  person David Wasser    schedule 07.01.2021
comment
Вы проверяли поведение на версиях до Android 11? Как выглядят журналы adb на версиях до Android 11?   -  person David Wasser    schedule 07.01.2021
comment
@ ginga_ninja217 Изменение архитектуры моей функции и превращение моего сервиса в связанный сервис решили мою проблему.   -  person Sergio Adrian Nunez    schedule 13.01.2021


Ответы (1)


Моя первоначальная цель состояла в том, чтобы получать обновления местоположения в действии B, пока наши пользователи все еще могли использовать приложение (Открыть другие действия). Сохранение Activity B было важно, потому что у него был WebView, который нельзя было перезагрузить, иначе пользователь потерял бы свой прогресс.

Мне удалось добиться этого с помощью флага единственного экземпляра в действии B, и, вероятно, это неправильный способ сделать это, поскольку ясно, что Google изменил способ управления задачами в новом обновлении Android 11.

Добавление другого taskAffinity к Activity B легко решило бы проблему уничтожения моей задачи, но оно создавало два окна в недавних приложениях, и это вызывало другие проблемы, если пользователь убивал окно с помощью Activity A.

Я изменил архитектуру своего решения, чтобы сделать мою Службу связанной службой, которая также может работать на переднем плане и содержать все необходимые данные, которые потребуются моему пользовательскому интерфейсу при повторном входе в действие B. https://developer.android.com/guide/components/bound-services

person Sergio Adrian Nunez    schedule 13.01.2021