服务的分类
Google官网将Android服务分为了三种,前台服务,后台服务和绑定服务:
- 前台
前台服务执行一些用户能注意到的操作。例如,音频应用会使用前台服务来播放音频曲目。前台服务必须显示通知。即使用户停止与应用的交互,前台服务仍会继续运行。
- 后台
后台服务执行用户不会直接注意到的操作。例如,如果应用使用某个服务来压缩其存储空间,则此服务通常是后台服务。
- 绑定
当应用组件通过调用 bindService()
绑定到服务时,服务即处于绑定状态。绑定服务会提供客户端-服务器接口,以便组件与服务进行交互、发送请求、接收结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。仅当与另一个应用组件绑定时,绑定服务才会运行。多个组件可同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
我个人理解服务可以分为两种,前台
和后台
,而绑定
应该是被当作一种状态,因为前台服务
和后台服务
都可以进行绑定。
和绑定状态一样,启动也应该是一种状态(service可以同时处于这两种状态),关键点在于我们是否实现一组回调方法:
onStartCommand()
(让组件启动服务)和onBind()
(实现服务绑定)。
基于这个理解,我们将限制分成了前台和后台两个部分:
后台服务限制
隐式启动限制
从 Android 5.0(API 级别 21)开始,如果使用隐式 Intent 调用 bindService()
,则系统会抛出异常。为确保应用的安全性,在启动 Service
时,请始终使用显式 Intent,且不要为服务声明 Intent 过滤器。
应用在后台时 Service的限制
在后台中运行的 Service 会消耗设备资源,这可能会降低用户体验。 为了缓解这一问题,系统对这些 Service 施加了一些限制。
处于前台时,应用可以自由创建和运行前台与后台 Service。
如果满足以下任意条件,应用将被视为处于前台:
- 具有可见 Activity(不管该 Activity 已启动还是已暂停)。
- 具有前台 Service。
- 另一个前台应用已关联到该应用(不管是通过绑定到其中一个 Service,还是通过使用其中一个内容提供程序)。 例如,如果另一个应用绑定到该应用的 Service,那么该应用处于前台:
- IME
- 壁纸 Service
- 通知侦听器
- 语音或文本 Service
如果以上条件均不满足,应用将被视为处于后台。
应用在后台创建后台service
Android 8.0 开始:系统不允许后台应用创建后台 Service。否则该函数将引发一个 IllegalStateException。
创建service之后 应用进入后台
Android 8.0 开始:进入后台时,在一个持续数分钟的时间窗内,应用仍可以创建和使用 Service。 在该时间窗结束后,应用将被视为处于空闲状态。 此时,系统将停止应用的后台 Service,就像应用已经调用 Service 的 Service.stopSelf()
方法一样。
注意:如果您的应用面向 API 级别 26 或更高版本,当应用本身未在前台运行时,系统会对运行后台服务施加限制。在诸如此类的大多数情况下,您的应用应改为使用计划作业。
为了解除这种限制,可以使用 JobScheduler
作业替换后台 Service。
后台服务升级前台限制
在 Android 8.0 之前,创建前台 Service 的方式通常是先创建一个后台 Service,然后将该 Service 推到前台。
而在Android 8.0 之后,系统不允许后台应用创建后台 Service。
解决方案:调用 startForegroundService()
,以在前台启动新 Service。
在系统创建 Service 后,应用有五秒的时间来调用该 Service 的 startForeground()
方法以显示新 Service 的用户可见通知。 如果应用在此时间限制内未调用 startForeground()
,则系统将停止此 Service 并声明此应用为 ANR。
前台服务
权限限制
前台服务必须显示优先级为 PRIORITY_LOW
或更高的状态栏通知,这有助于确保用户知道应用正在执行的任务。如果某操作不是特别重要,因而您希望使用最低优先级通知,则可能不适合使用服务;相反,您可以考虑使用计划作业。
在 Android 9 (API 28)之后,使用前台服务必须申请FOREGROUND_SERVICE
权限,否则会报SecurityException
。 这是普通权限,因此,系统会自动为请求权限的应用授予此权限。
每个运行服务的应用都会给系统带来额外负担,从而消耗系统资源。如果应用尝试使用低优先级通知隐藏其服务,则可能会降低用户正在主动交互的应用的性能。因此,如果某个应用尝试运行拥有最低优先级通知的服务,则系统会在抽屉式通知栏的底部调用出该应用的行为。
前台服务启动限制
以 Android 12 为目标平台的应用在后台运行时无法再启动前台服务。
特殊情况:在以下情况下,即使您的应用在后台运行,也可以启动前台服务:
您的应用从某种用户可见的状态,例如某种 activity,过渡至其他状态。
您的应用使用 Firebase Cloud Messaging 接收一条高优先级消息。
设备重新启动并在广播接收器中接收了
ACTION_BOOT_COMPLETED
intent 操作之后。您的应用使用 Companion Device Manager。
您的应用已请求
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
权限,并将用户导向至用户已在其中停用该应用的电池优化功能的设置页面。如需将用户引导至系统设置中的电池优化页面,请调用包含
ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
intent 操作的 intent。在该页面上,当用户关闭应用的电池优化功能后,系统将显示图 1 所示的对话框。应用满足限制从后台启动 activity 的例外情况中所述的任何条件,但应用在现有任务的返回堆栈中具有 activity 的情况除外。
功能限制
在Android 11及以后,系统对前台服务何时可以访问设备的位置、摄像头或麦克风进行了限制。
如果您的应用以 Android 11 或更高版本为目标平台,且在前台服务中访问摄像头或麦克风,则必须添加前台服务类型 camera
和 microphone
。
<manifest>
...
<service ...
android:foregroundServiceType="location|camera|microphone" />
</manifest>
如果你的应用在后台运行时启动了某项前台服务:
- 服务无法获取用户
地理位置
权限,除非用户获取了ACCESS_BACKGROUND_LOCATION
权限; - 服务无法获取
麦克风
和摄像头
的权限。
特殊情况: 系统应用、应用微件(app widgets)、有与之互动的notification 、应用有START_ACTIVITIES_FROM_BACKGROUND特权。
判断功能是否受限制
如果某服务的功能(位置、麦克风 和 相机)受到了限制,则Logcat中会打印如下语句:
Foreground service started from background can not have \
location/camera/microphone access: service SERVICE_NAME