本文主要是对谷歌开发者官方微信公众号发布的【中文教学视频】Android Oreo 中的后台进程等文章的学习记录。
为了流畅的用户体验,从 API 26开始,Android 对后台服务引入了严格的限制。基本上,除非应用在前台运行,否则系统将在几分钟内停止应用的所有后台服务(2018年2月8日:经笔者在Nexus 5X、Android系统版本8.1下测试,实际能停留的时间只有一分钟)。
概览
- Service+广播: 面向O+ 或者用户选择启用
- Service
- 不能在后台启动Service:
- 无startService
- 不能向pendingIntent封装Service发送信息
- 从前台到后台: Service关闭
- 从后 台 到 前 台: startForegroundService
- 不能在后台启动Service:
- 广播
- 不能在清单中注册隐式广播
- 存在一个简短的白名单
- 位置
- 影响所有目标平台的应用
Service限制
将影响通过隐式广播启动的应用和从后台启动服务的应用
从后台调用startService,将触发IllegalStateException异常。
前台应用的定义
- 处于前台的Activity(已启动/暂停)
- 它具有前台Service。(前台Service创建流程有所变化)
- 另一个前台应用通过绑定或使用内容提供器连接到该应用,如:
- IME
- 壁纸Service
- 通知侦听器
- 语音或文本Service
影响所有后台Service
包括IntentService、启动服务的PendingIntent(可以创建、但在后台发送时会受影响)、将要提到前台的后台Service(在后台启动并准备提升为前台服务的服务)
针对Service的选项
- 计划作业JobScheduler
- FirebaseJobDispatcher
- JobIntentService(替代IntentService)
- 临时服务白名单(FCM/GCM)
下列特殊情形,应用会被列入临时服务白名单,可以在短时间内像在前台一样运行:
- 高优先级FCM/GCM
- 短信/彩信传输
- 来自通知的操作
startForegroundService(将始终显示在屏幕上以告知客户正在运行)
新的创建流程:- startForegroundService(Intent service)
- 发布优先级至少为LOW的通知
- startForeground(int id, Notification notification)
必须严格按照上面的步骤流程创建前台应用,如果只调用startForegroundService,会出现运行时异常,应用将直接停止运行:
02-08 11:48:51.455 D/AndroidRuntime: Shutting down VM
02-08 11:48:51.457 E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.sy.androidofeatures, PID: 7139
android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1768)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
- 延迟至应用处于前台
adb测试命令
#让应用在后台运行
adb shell am make-uid-idle <package>
#强制允许和禁止后台运行
adb shell cmd appops set <package> RUN_IN_BACKGROUND allow
adb shell cmd appops set <package> RUN_IN_BACKGROUND deny
广播限制
静态定义并监听隐式广播的广播接收器不会接收这些广播
隐式广播:无target component属性
静态接收器:定义于AndroidManifest.xml
针对静态隐式广播接收器的选项
- 隐式广播限制白名单,参考文末文档
- 作业JobScheduler
可适用作业代替的情况:
- 网络连接变更(按流量计费的网络)
- 充电状态
- 观察到内容提供器程序URI发生变化
- 存储空间过低(8.0新增)
- 电池电量过低(8.0新增)
- 动态广播
后台位置限制
为降低功耗,无论应用的目标 SDK 版本为何,Android 8.0 都会对后台应用检索用户当前位置的频率进行限制。
受影响的 API
- Fused Location Provider (FLP)
- Geofencing
- GNSS Measurements 和 GNSS Navigation Messages
- Location Manager
提供给后台应用的位置更新只会根据 Android 8.0 行为变更中定义的间隔,按每小时几次的频率提供。 - WLAN 管理器
startScan() 方法对后台应用执行完整扫描的频率仅为每小时数次。如果不久之后后台应用再次调用此方法, WifiManager 类将提供上次扫描所缓存的结果。