Android 11 - 按下主页按钮时触发前台服务 onTaskRemoved
Android 11 - foregroundService's onTaskRemoved is trigged when home button pressed
我在 Pixel 4XL (Android 11) 上看到一些奇怪的行为。
我的前台服务的 onTaskRemoved 被意外调用。
这不会发生在任何其他设备上,但我没有任何其他 Android 11 设备,模拟器无法执行 BLE。
我的应用程序使用正在进行的 BLE 连接与另一个非 android 设备通信。
前台服务用于确保程序保持活动状态以接收来自设备的 BLE 通信。
它并不总是发生,但在大多数情况下(75% 的时间)按下主页(在 Pixel 4XL 上从屏幕底部向上滑动)后,这将导致前台服务的 onTaskRemoved 被调用。
在我的应用程序中打开一个不同的 activity(即 MainActivity 以外的 activity)几乎可以保证会发生这种情况。
从通知栏打开设置然后滑动主页仍然会触发这种情况,所以我不会不小心杀死应用程序,因为我在设置应用程序处于焦点时向上滑动。
根据我的理解,只有当用户通过在任务切换器中滑动来终止应用程序时,才会触发此方法。
如果我回到任务切换器,在服务被终止后,我的应用程序仍然可用并显示最后 activity 打开的状态。切换到它会恢复到正确的位置,因此应用程序本身一定没有终止。
phone 已插入充电中,因此它不应该和 doze/sleeping 正常工作。
这可能会在启动应用程序后 60 秒内发生,而不是 30 分钟。
这到底是怎么回事?
我唯一能想到的是,出于某种原因,它不被视为前台服务。在 onTaskRemoved 期间或前后 logcat 中没有错误。我不会在代码中的任何地方自己调用 onTaskRemoved。
我试过使用 dumpsys in this post,但它似乎有所不同,我找不到任何提到的参考资料。
通知本身是这样列出的:
$ adb shell dumpsys activity services | grep foreground
isForeground=true foregroundId=13459 foregroundNoti=Notification(channel=xxxService shortcut=null contentView=null vibrate=null sound=null tick defaults=0x0 flags=0x62 color=0x00000000 actions=1 vis=PRIVATE)
是的,我在清单中设置了前台权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
BLEService onCreate 方法(删除了一些不相关的):
@Override
public void onCreate()
{
BLEManager.getInstance(getApplicationContext());
startForeground(
NotificationHandler.NOTIFICATION_BTCONNECTION_ID,
NotificationHandler.getInstance(getApplicationContext()).createConnectionNotification(getApplicationContext(), MainActivity.class, R.drawable.navigation_tab, R.drawable.baseline_clear_black_24, getString(R.string.myDevice_text_disconnect), getString(R.string.app_name), getString(R.string.bleService_text_connected), getString(R.string.bleService_text_connected))
);
}
通知渠道:
NotificationChannel serviceChannel;
serviceChannel = new NotificationChannel(
NOTIFICATION_SERVICE_CHANNEL_ID,
serviceNotificationChannelLabel,
NotificationManager.IMPORTANCE_HIGH
);
serviceChannel.setDescription(serviceNotificationChannelDescription);
serviceChannel.enableLights(false);
serviceChannel.setShowBadge(false);
serviceChannel.enableVibration(false);
mNotificationManager.createNotificationChannel(serviceChannel);
通知:
NotificationCompat.Builder nBuilder = new NotificationCompat.Builder(context, NOTIFICATION_SERVICE_CHANNEL_ID)
.setSmallIcon(icon)
.setContentTitle(contentTitle)
.setContentText(contentText)
.setContentIntent(pLaunchIntent)
.setTicker(tickerText)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setOngoing(true)
.setAutoCancel(false)
.addAction(icButton1, button1Text, actionPendingIntent);
return nBuilder.build();
对我来说,将 activity 启动模式从 singleInstance
更改为解决了问题。
改变
android:launchMode="singleInstance"
至
android:launchMode="singleTop"
或完全删除它
显然,使用 singleInstance 是有正当理由的,这仍然是意外行为,但目前它是一个有效的解决方法。
我在 Pixel 4XL (Android 11) 上看到一些奇怪的行为。 我的前台服务的 onTaskRemoved 被意外调用。 这不会发生在任何其他设备上,但我没有任何其他 Android 11 设备,模拟器无法执行 BLE。
我的应用程序使用正在进行的 BLE 连接与另一个非 android 设备通信。 前台服务用于确保程序保持活动状态以接收来自设备的 BLE 通信。
它并不总是发生,但在大多数情况下(75% 的时间)按下主页(在 Pixel 4XL 上从屏幕底部向上滑动)后,这将导致前台服务的 onTaskRemoved 被调用。
在我的应用程序中打开一个不同的 activity(即 MainActivity 以外的 activity)几乎可以保证会发生这种情况。
从通知栏打开设置然后滑动主页仍然会触发这种情况,所以我不会不小心杀死应用程序,因为我在设置应用程序处于焦点时向上滑动。
根据我的理解,只有当用户通过在任务切换器中滑动来终止应用程序时,才会触发此方法。
如果我回到任务切换器,在服务被终止后,我的应用程序仍然可用并显示最后 activity 打开的状态。切换到它会恢复到正确的位置,因此应用程序本身一定没有终止。 phone 已插入充电中,因此它不应该和 doze/sleeping 正常工作。 这可能会在启动应用程序后 60 秒内发生,而不是 30 分钟。
这到底是怎么回事? 我唯一能想到的是,出于某种原因,它不被视为前台服务。在 onTaskRemoved 期间或前后 logcat 中没有错误。我不会在代码中的任何地方自己调用 onTaskRemoved。
我试过使用 dumpsys in this post,但它似乎有所不同,我找不到任何提到的参考资料。
通知本身是这样列出的:
$ adb shell dumpsys activity services | grep foreground
isForeground=true foregroundId=13459 foregroundNoti=Notification(channel=xxxService shortcut=null contentView=null vibrate=null sound=null tick defaults=0x0 flags=0x62 color=0x00000000 actions=1 vis=PRIVATE)
是的,我在清单中设置了前台权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
BLEService onCreate 方法(删除了一些不相关的):
@Override
public void onCreate()
{
BLEManager.getInstance(getApplicationContext());
startForeground(
NotificationHandler.NOTIFICATION_BTCONNECTION_ID,
NotificationHandler.getInstance(getApplicationContext()).createConnectionNotification(getApplicationContext(), MainActivity.class, R.drawable.navigation_tab, R.drawable.baseline_clear_black_24, getString(R.string.myDevice_text_disconnect), getString(R.string.app_name), getString(R.string.bleService_text_connected), getString(R.string.bleService_text_connected))
);
}
通知渠道:
NotificationChannel serviceChannel;
serviceChannel = new NotificationChannel(
NOTIFICATION_SERVICE_CHANNEL_ID,
serviceNotificationChannelLabel,
NotificationManager.IMPORTANCE_HIGH
);
serviceChannel.setDescription(serviceNotificationChannelDescription);
serviceChannel.enableLights(false);
serviceChannel.setShowBadge(false);
serviceChannel.enableVibration(false);
mNotificationManager.createNotificationChannel(serviceChannel);
通知:
NotificationCompat.Builder nBuilder = new NotificationCompat.Builder(context, NOTIFICATION_SERVICE_CHANNEL_ID)
.setSmallIcon(icon)
.setContentTitle(contentTitle)
.setContentText(contentText)
.setContentIntent(pLaunchIntent)
.setTicker(tickerText)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setOngoing(true)
.setAutoCancel(false)
.addAction(icButton1, button1Text, actionPendingIntent);
return nBuilder.build();
对我来说,将 activity 启动模式从 singleInstance
更改为解决了问题。
改变
android:launchMode="singleInstance"
至
android:launchMode="singleTop"
或完全删除它
显然,使用 singleInstance 是有正当理由的,这仍然是意外行为,但目前它是一个有效的解决方法。