Мой текущий поток следующий:
Метод, который запускает службу переднего плана
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 и предыдущей версии.
Действие 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, которое содержит работающую службу.
@CommonsWare Я внес изменения в свой пост, чтобы уточнить, что я не использую обратную навигацию как таковую, а начинаю новую активность, возвращаясь к исходной. Еще одна вещь, которую я хочу уточнить, заключается в том, что действие B — это отдельный экземпляр, поэтому оно принадлежит отдельной задаче, отличной от действия A.
@ Адриан, вы пытались запустить службу как связанную службу из действия B, а затем переместить ее на передний план после уничтожения действия B?
Пожалуйста, отредактируйте свой вопрос и опубликуйте содержимое вашего манифеста. По крайней мере, объявления для 2 видов деятельности и службы.
Как ActivityA запускается ActivityB и наоборот?
@DavidWasser Я отредактировал свой пост с учетом ваших предложений, спасибо!
Здесь есть ряд вопросов, которые, безусловно, сбивают с толку. Вы объявили ActivityB с launchMode=:"singleInstance", но не указали taskAffinity. Это означает, что когда ActivityA запускает ActivityB, режим запуска игнорируется и ActivityB запускается в той же задаче, что и ActivityA. Это может быть или не быть тем, что вы хотели. Вы можете проверить это, запустив ActivityB из ActivityA, а затем используя adb shell dumpsys activity activities, и вы должны увидеть только 1 задачу для своего приложения (а не 2).
Итак, теперь у вас есть задача с ActivityA как root и ActivityB вдобавок к этому. Когда ActivityB теперь запускает ActivityA с помощью флагов CLEAR_TOP и SINGLE_TOP, ActivityB удаляется из задачи (завершается), и пользователь возвращается к исходному экземпляру ActivityA. Вы также должны увидеть это с помощью adb shell dumpsys activity activities. Поскольку ActivityB закончен, в какой-то момент onDestroy() будет вызван. Это также должно быть поведение до Android 11.
Чтобы помочь вам, проверьте свой код как на Android 11, так и на более ранней версии Android, и с помощью команд adb shell определите, есть ли у вас 1 задача или 2. Я не понимаю, как у вас может быть 2 задачи, поскольку taskAffinity переопределяет launchMode, и оба действия имеют одинаковое значение. (по умолчанию) taskAffinity. Пожалуйста, сообщите нам о своих выводах (вы можете отредактировать свой вопрос и добавить соответствующую информацию), и тогда я смогу внести другие предложения.
Похоже, что в Android 11 есть некоторые изменения в поведении taskAffinity. Я не проверял это сам, но я уже ответил на этот вопрос, ситуация похожа на вашу: stackoverflow.com/questions/64769530/… Мне нужно провести дополнительное исследование, чтобы действительно понять, что изменилось.
@DavidWasser Я обновил свой вопрос, чтобы показать журналы Android 11. Я проверил действия, и было создано две задачи с одним и тем же taskAffinity. Я также обнаружил, что в Android 11, когда у вас есть более одной задачи с одинаковым сходством, после того, как я сворачиваю свое приложение, наименее используемая задача уничтожается, это поведение вызывает мою проблему.
Опубликуйте запись манифеста для SpringBoardActivity, которая является корнем Activity задачи.
Вы проверяли поведение на версиях до Android 11? Как выглядят журналы adb на версиях до Android 11?
@ ginga_ninja217 Изменение архитектуры моей функции и превращение моего сервиса в связанный сервис решили мою проблему.
Моя первоначальная цель состояла в том, чтобы получать обновления местоположения в действии B, пока наши пользователи все еще могли использовать приложение (Открыть другие действия). Сохранение Activity B было важно, потому что у него был WebView, который нельзя было перезагрузить, иначе пользователь потерял бы свой прогресс.
Мне удалось добиться этого с помощью флага единственного экземпляра в действии B, и, вероятно, это неправильный способ сделать это, поскольку ясно, что Google изменил способ управления задачами в новом обновлении Android 11.
Добавление другого taskAffinity к Activity B легко решило бы проблему уничтожения моей задачи, но оно создавало два окна в недавних приложениях, и это вызывало другие проблемы, если пользователь убивал окно с помощью Activity A.
Я изменил архитектуру своего решения, чтобы сделать мою Службу связанной службой, которая также может выходить на передний план и содержать все необходимые данные, которые потребуются моему пользовательскому интерфейсу при повторном входе в действие B. https://developer.android.com/guide/components/bound-services
«если пользователь возвращается к действию A, а затем сворачивает приложение, OnDestroy() вызывается для действия B» — это стандартное поведение для обратной навигации (уничтожает действие, которое было на переднем плане, и возвращает управление предыдущему действию на заднем стеке). Так было с Android 1.0. «активность B, которая содержит работающую службу» —
startForegroundService()не привязывает службу к конкретной активности иstartForegroundService()не препятствует работе обратной навигации.