每次在后台运行时,应用都会消耗一部分有限的设备资源,例如 RAM。 这可能会影响用户体验,如果用户正在使用占用大量资源的应用(例如玩游戏或观看视频),影响尤为明显。
为了提升用户体验,Android 8.0 对应用在后台运行时可以执行的操作施加了限制。
其中,Not allowed to start service Intent app is in background 是后台服务限制引起的。[1]
在后台中运行的服务会消耗设备资源,这可能降低用户体验。 为了缓解这一问题,系统对这些服务施加了一些限制。
系统可以区分 前台 和 后台 应用。如果满足以下任意条件,应用将被视为处于前台:
如果以上条件均不满足,应用将被视为处于后台。[1]
处于前台时,应用可以自由创建和运行前台服务与后台服务。 进入后台时,在一个持续数分钟的时间窗内,应用仍可以创建和使用服务。
在该时间窗结束后,应用将被视为处于 空闲(idle) 状态。 此时,系统将停止应用的后台服务,就像应用已经调用服务的“Service.stopSelf()”方法。[1]
注:将应用不显示在前台,然后调用如下命令,直接把应用的状态由 active 至 idle。[2]
adb shell am make-uid-idle
Android 8.0 引入了一种全新的方法,即 Context.startForegroundService()。
在系统创建服务后,应用有五秒的时间来调用该服务的 startForeground() 方法以显示新服务的用户可见通知。
如果应用在此时间限制内未调用 startForeground(),则系统将停止服务并声明此应用为 ANR。
if (VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ctx.startForegroundService(getVSPushService(ctx));
} else {
ctx.startService(getVSPushService(ctx));
}
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String NOTIFICATION_CHANNEL_ID = "package_name";
String channelName = "My Background Service";
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID,channelName, NotificationManager.IMPORTANCE_LOW);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.createNotificationChannel(channel);
Notification notification = new Notification.Builder(this,NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher) // the status icon
.setWhen(System.currentTimeMillis()) // the time stamp
.setContentText("IM服务正在运行") // the contents of the entry
.build();
startForeground(2, notification);
}
}
比如我就是想在后台启用 service, Android 8.0 及以上只能通过 startForegroundService 的方式进行启动,这样会在通知栏常驻一个通知。那么我是否可以调用 startForeground() 之后立马调用 stopForeground 来消除改通知?
是的,是可以做到上述效果,但是之后会出现什么呢?
02-13 20:03:39.968 1307 1326 W ActivityManager: Stopping service due to app idle: u0a404 -1m0s113ms packageName/ServiceName
观察日志,会发现出现上述的内容,也就是在1分钟后,该Service 依旧会被结束。所以这种方式行不通。
[1] : https://developer.android.com/about/versions/oreo/background “Background Execution Limits”
[2] : https://xiaozhuanlan.com/topic/2487365091 “从源码角度看 Android O AMS 新特性”
[3] : https://github.com/zengjingfang/AndroidBox/issues/23 “Android8.0系统:.RemoteServiceException: Bad notification for startForeground”