根源:Android 8.0以后,谷歌开始收紧Service权限。主要表现的两个方面:
1)服务前台化
不再支持原来单纯的后台服务,启动服务需要前台化启动。
Intent intent = new Intent(context, DownloadCenterService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
// Pre-O behavior.
context.startService(intent);
}
未切换前台化启动,会出现闪退情况。Android8.0后不允许直接启动后台服务。
Process: com.icourt.alpha.service.LocalService, PID: 4343
java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.icourt.alpha/.service.LocalService }: app is in background uid UidRecord{81da92c u0a91 SVC bg:+1m0s13ms idle procs:4 seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1505)
at android.app.ContextImpl.startService(ContextImpl.java:1461)
at android.content.ContextWrapper.startService(ContextWrapper.java:644)
at com.icourt.alpha.service.RemoteService$RemoteServiceConnection.onServiceDisconnected(RemoteService.java:100)
at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1627)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1663)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
2)前台服务需要附加一个前台通知
要求服务启动以后5秒内必须创建好一个前台通知。
@Override
public void onCreate() {
super.onCreate();
// 创建服务前台通知
createForegroundNotification();
}
/**
* 创建服务前台通知
*
* @author zhouronghua
* @time 2020/7/22 4:15 PM
*/
private void createForegroundNotification() {
if (OSVersionUtils.hasO()) {
// 8.0以上机型启动一个空的前台通知
try {
startForeground(SERVICE_NOTIFY_ID, createServiceNotify());
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 初始化通知对象(服务初始化使用)
*
* @author zhouronghua
* @time 19-3-28 下午9:12
*/
public Notification createServiceNotify() {
Notification notification = null;
try {
if (OSVersionUtils.hasO()) {
NotificationChannel channel = new NotificationChannel(SERVICE_CHANNEL_ID, SERVICE_CHANNEL_NAME,
NotificationManager.IMPORTANCE_LOW);
channel.enableVibration(false);
channel.enableLights(false);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.createNotificationChannel(channel);
}
notification = (new NotificationCompat.Builder(this, SERVICE_CHANNEL_ID)).build();
} catch (Exception var3) {
var3.printStackTrace();
}
return notification;
}
这是通用的Android8.0以后Service的启动方案。
如果你以为这样就可以了,那不好意思,同学,你是不知道社会的险恶呀。
android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2220)
at android.os.Handler.dispatchMessage(Handler.java:109)
at android.os.Looper.loop(Looper.java:166)
at android.app.ActivityThread.main(ActivityThread.java:7555)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:469)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:963)
这样修改以后,Servie友盟的崩溃,能够从4000多下降到800~900,仍然会出现一些闪退。
5秒陷阱并不能够完全解决。
从此,Android8.0以后,作为安卓4大组件的Service开始沦为鸡肋。
谷歌推荐使用WorkManager架构组件来管理后台工作任务。
WorkManager是Jetpack中一个重要组件。WorkManager相对于Service主要有以下优势:
1.service的滥用导致手机后台任务不断执行,耗电量大。
2.从开发者来说,Android8.0以后,Android对于后台service管理的更加严格,应用在后台启动的服务必须是前台服务,否则会导致应用crash。当然你也可以选择降低targetSdkVersion。
3.针对targetSdkVersion Google也针对的出了一些限制。ps:2019 年起,每次发布新版本后,所有应用都必须在一年内将 Target API 更新到最新版本。
国内对于APP权限的合规和使用进一步严格,要求APP的目标SDK版本必须为26,使用动态授权的方式,随着系统版本的更新,也进一步压缩了Service的生存空间。
因此,将Service进行相应的替代就变得迫切了。
的生存空间。