Android O 创建后台Service
一、服务分类
(1)运行类型
- 前台服务:用户可以看到,如音乐播发器,在通知栏显示通知。优先级高,不会因系统内存不足被回收。
- 后台服务:用户无法看到,如天气服务,日期更新
(2)功能分类
- 不可通信的服务:用startservice启动
- 可通信的后台服务:用bindservice启动
二、服务的两种启动方法
(1)Startservice启动特点
- 生命周期:startservice---oncreate---onstartcommand---running---ondestroty
- 无法与调用者通信
- 外部调用stopservice或者stopself,服务才会停止运行并销毁
- 多次startservice不会调用oncreate,会调用onstartcommand;可根据传入的intent进行实际的操作。比如音乐视频播放进度。
(2)bindservie特点
- 生命周期bindservice---oncreate---onbind---running---unbind---ondestroty
- Client可通过binder与service通信
- 调用者销毁时,解除与service绑定,也可调用unbinder方法解除
Service 的设计逻辑是,如果我们调用了 startService 就必须调用 stopService 或者 stopSelf 才能关闭服务,如果我们调用了 bindService 就必须调用 unbindService 才能关闭服务,start 与 stop,bind 与 unbind 必须一一对应。
三、Android O 启动后台服务
从android O (sdk:26以后)开始,后台应用不允许通过startservice创建后台服务。
补充知识点:一个应用可以有一个或者多个进程,当任何一个进程变为被转换成前台可见进程的时候,APP都会被认作前台应用
(1)第一个问题:后台应用为什么不允许startservice启动服务
例如,用户可以在一个窗口中玩游戏,同时在另一个窗口中浏览网页,并使用第三个应用播放音乐。
同时运行的应用越多,对系统造成的负担越大。 如果还有应用或服务在后台运行,这会对系统造成更大负担,进而可能导致用户体验下降;例如,音乐应用可能会突然关闭。为了降低发生这些问题的几率,Android 8.0 对应用在用户不与其直接交互时可以执行的操作施加了限制。
应用程序在后台,通过startservice启动服务,报错:Not allowed to start service Intent XXX : app is in background uid UidRecord
通过源码查看,看看当前app进程是否处于后台非激活状态,如果是的话 ,就不会允许startservice
模拟后台应用startservice启动服务:Android O 后台startService限制简析-阿里云开发者社区 (aliyun.com)
绑定服务不受此影响
(2)第二个问题:如果想在后台应用通过startservice启动服务,如何兼容?
- ContextCompat.startForegroundService(MainActivity.this, new Intent(MainActivity.this, MyService.class));//系统自动判断版本
- notification:在service.oncreate()生命周期方法里添加通知,设置通知栏消息(可隐藏),调用service.startForeground方法,设置为前台服务
@Override public void onCreate() { setServiceForeground(); super.onCreate(); } /** * 设置前台服务 */ private void setServiceForeground() { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { String channelId = getPackageName(); NotificationChannel notificationChannel = new NotificationChannel( channelId, "name", NotificationManager.IMPORTANCE_LOW); notificationChannel.setSound(null, null); NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); manager.createNotificationChannel(notificationChannel); Notification.Builder builder = new Notification.Builder(this); builder.setTicker(""); builder.setContentTitle(""); builder.setContentText(""); builder.setChannelId(channelId); builder.setSmallIcon(R.mipmap.ic_launcher); Notification notification = builder.build(); startForeground(223, notification); } else { Notification.Builder builder = new Notification.Builder(this); builder.setSound(null); builder.setPriority(Notification.PRIORITY_LOW); builder.setTicker(""); builder.setContentTitle(""); builder.setContentText(""); Notification notification = builder.build(); startForeground(223, notification); }
3.pessimision
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />