Android 5 到 16 期间 service 的发展

Service 基础知识

Service 和 Activity 一样都是 Android 的组件。它们最大的区别就是 service 没有 UI 而 Activity 有。

Service 默认运行在当前进程的主线程,这点和 activity 是一样的。因此 Service 要么会在配置处设置其他进程,要么是在 Service 代码中启动新的线程。

Service在清单文件中的声明

xml 复制代码
 <service
    android:name=".MyCustomService"
    android:exported="true"
    android:enabled="true"
    android:process=":my_service_process"
    android:isolatedProcess="true"
    android:permission="com.example.permission.START_MY_SERVICE"/>
  • android:exported:代表是否能被其他应用隐式调用,其默认值是由service中有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false。为false的情况下,即使有intent-filter匹配,也无法打开,即无法被其他应用隐式调用。
  • android:name:对应Service类名,必选
  • android:permission:是权限声明
  • android:process:是否需要在单独的进程中运行,当设置为android:process=":remote"时,代表Service在单独的进程中运行。注意":"很重要,它的意思是指要在当前进程名称前面附加上当前的包名,所以"remote"和":remote"不是同一个意思,前者的进程名称为:remote,而后者的进程名称为:App-packageName:remote。
  • android:isolatedProcess :设置 true 意味着,服务会在一个特殊的进程下运行,这个进程与系统其他进程分开且没有自己的权限。与其通信的唯一途径是通过服务的API(bind and start)。
  • android:enabled:是否可以被系统实例化,默认为 true因为父标签 也有 enable 属性,所以必须两个都为默认值 true 的情况下服务才会被激活,否则不会激活。

Service 的种类

Service 有三种:

  • 后台服务
  • 绑定服务
  • 前台服务

其中后台服务,是通过 startService 启动的,除非调用 stopSelf 或者 stopService ,否则该服务会一直运行。绑定服务,是通过 bindService 启动的,当绑定的数量为 0 时,该服务会自动停止。 如果调用bindService()方法前服务已经被绑定,多次版调用bindService()方法并不会导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。多次调用 startService 会报错

  • 先启动再绑定

我们也可以使用 bindService 来绑定已经启动的服务。此时停止服务需要调用 unbindServicestopService

  • 先绑定再启动

如果当前Service实例先以绑定状态运行,然后再以启动状态运行,那么绑定服务将会转为启动服务运行,这时如果之前绑定的宿主(Activity)被销毁了,也不会影响服务的运行,服务还是会一直运行下去,指定收到调用停止服务或者内存不足时才会销毁该服务。

生命周期

其中 onStartCommand 的返回值有:

  • START_NOT_STICKY:如果系统在 onStartCommand() 返回后终止服务,请不要重新创建服务,除非有待传递的待处理 intent。这是最安全的选项,可避免在不需要时运行服务,以及在应用可以简单地重启所有未完成的作业时运行服务。
  • START_STICKY:如果系统在 onStartCommand() 返回后终止服务,请重新创建服务并调用 onStartCommand(),但不要重新传递上一个 intent。相反,除非有待处理的 intent 用于启动服务,否则系统会使用 null intent 调用 onStartCommand()。在这种情况下,系统会传递这些 intent。这适用于未执行命令但无限期运行并等待作业的媒体播放器(或类似服务)。
  • START_REDELIVER_INTENT:如果系统在 onStartCommand() 返回后终止服务,请重新创建服务,并使用传递给服务的最后一个 intent 调用 onStartCommand()。系统会依次传送所有待处理 intent。这适用于正在积极执行应立即恢复的作业的服务,例如下载文件。

Android 5 到 16 期间后台服务的变更

应用满足以下任一条件即视为前台应用:

  • 它具有可见的 Activity,无论 Activity 处于启动还是暂停状态。
  • 它具有前台服务。
  • 另一个前台应用已关联到该应用(不管是通过绑定到其中一个服务,还是通过使用其中一个 content >provider)。例如,如果其他应用绑定到该应用的以下任一项,则该应用处于前台:
  • IME
  • 壁纸服务
  • 通知侦听器
  • 语音或文本服务 如果以上所有条件均不满足,应用即视为后台应用。

Android 5 开始,使用隐式 intent 启动服务,系统会抛出异常。这时,我们可以设置应用的包名来解决

scss 复制代码
final Intent serviceIntent=new Intent(); serviceIntent.setAction("com.android.ForegroundService");
serviceIntent.setPackage(getPackageName());//设置应用的包名
startService(serviceIntent);

Android 8开始则对后台服务进行限制。当应用进入后台时,会有几分钟时间来创建和使用服务。该段时间结束后,应用会被视为处于空闲状态。此时,系统会停止应用的后台服务,就像应用已调用这些服务的 Service.stopSelf() 方法一样。

android 8 时, IntentService 被废弃,推荐使用 workmanager代替

Android 9 则限制了后台应用访问麦克风、摄像头、传感器等

前台服务

kotlin 复制代码
// 启动服务
val intent = Intent()
context.startForegroundService


// startForeground 来把服务提升到前台
class MyCameraService: Service() {

    private fun startForeground1() {
        
        try {
            val notification = NotificationCompat.Builder(this, "CHANNEL_ID")
                // Create the notification to display while the service is running
                .build()
           startForeground(
                /* id = */ 100, // Cannot be 0
                /* notification = */ notification,
               /* foregroundServiceType = */
               if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                   ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
               } else {
                   0
               },
            )
        } catch (e: Exception) {
           
        }
    }
}

stopSelfstopService 会停止服务。如需从前台移除服务,请从服务内部调用 stopForeground(int)。此方法接受一个布尔值,用于指示是否也移除状态栏通知。该服务会继续运行,但不再是前台服务。

前台服务的限制

Android 9,使用前台服务前需要请求 FOREGROUND_SERVICE 权限

Android 10,引入了 foregroundServiceType XML 清单属性,为前台服务定义对应的服务类型。比如 dataSync 是指从网络下载文件;mediaPlayback 是指播放音乐等。同时要求前台服务使用位置信息时,必须声明服务类型为 location

Android 11,当前台服务使用摄像头和麦克风时,应用必须声明其类型为 camera 或者 microphone

Android 12,应用在后台运行时,不能启动前台服务

Android 14 强制要求所有的前台服务声明其类型。除此之外,还需要设置权限类型,比如如果应用启动使用相机的前台服务,您必须同时请求 FOREGROUND_SERVICE 和 FOREGROUND_SERVICE_CAMERA 权限。

Android 15 则限制了不同类型的前台服务的运行时长限制。比如:系统允许 dataSync 和 mediaProcessing 前台服务在 24 小时内总共运行 6 小时,之后系统会调用正在运行的服务的 Service.onTimeout(int, int) 方法,这时有几秒钟的时间来调用 Service.stopSelf()。当系统调用 Service.onTimeout() 时,该服务不再被视为前台服务。如果服务未调用 Service.stopSelf(),系统会抛出内部异常。用户将应用置于前台,计时器会重置,应用可使用 6 小时

参考

相关推荐
Android小码家5 小时前
Android8.0+Camera2编译&烧录&源码研习
android·framework
消失的旧时光-19436 小时前
Kotlin 高阶函数在回调设计中的最佳实践
android·开发语言·kotlin
AI智能架构工坊7 小时前
提升AI虚拟健康系统开发效率:架构师推荐10款低代码开发平台
android·人工智能·低代码·ai
百锦再7 小时前
低代码开发的约束性及ABP框架的实践解析
android·开发语言·python·低代码·django·virtualenv·rxjava
那我掉的头发算什么8 小时前
【数据库】navicat的下载以及数据库约束
android·数据库·数据仓库·sql·mysql·数据库开发·数据库架构
明道源码9 小时前
Android Studio 应用运行到真机设备
android·ide·android studio
生莫甲鲁浪戴9 小时前
Android Studio新手开发第二十五天
android·ide·android studio
Varpb9 小时前
android studio-设置android模拟器屏幕自动旋转
android·android studio
2501_9151063210 小时前
iOS 打包 IPA 全流程详解,签名配置、工具选择与跨平台上传实战指南
android·macos·ios·小程序·uni-app·cocoa·iphone