Search code examples
androidandroid-serviceforeground-serviceandroid-11

What configuration do I need, to avoid Android 11 killing my SingleInstance Activity after minimizing from my main task?


My current flow is the following:

  1. The user enters the main activity A
  2. The user then launches activity B which is a single instance
  3. Activity B then starts a foreground service

Method that starts the foreground service

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

Service onStartCommand

Notification notification = getNotification();

startForeground(1, notification);

return START_NOT_STICKY;

Manifest

<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" />

The following actions keep my single instance alive on Android 11 and previous version.

  1. If activity B is minimized, the foreground service stays alive.
  2. If the user starts activity A from activity B (singleInstance), the foreground service stays alive.

Activity A launches B:

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

Logs:

* 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}

Activiy B launches A:

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

Logs:

* 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

But in Android 11, unlike previous Android versions, if the user starts activity A from activity B(singleInstance), then minimizes the app, OnDestroy() is called on activity B which holds a running Service.


Solution

  • My original goal was to obtain location updates in Activity B while our users could still use the app (Open other activities). Keeping Activity B alive was important because it had a WebView that couldn't be reloaded otherwise the user would lose their progress.

    I was able to achieve this with the single instance flag on activity B, and probably not the correct way of doing this since it’s clear that Google changed the way of managing tasks in the new Android 11 update.

    Adding a different taskAffinity to Activity B would’ve easily solved this issue of my task being killed, but it created two windows in the recent apps and that caused other issues if the user killed the window with Activity A.

    I re-architectured my solution to make my Service a bound service that could also go to the foreground, and it would contain all the necessary data that my UI would need when re-entering Activity B. https://developer.android.com/guide/components/bound-services