Service详解
1. 概述
在Android中,Service是一种应用程序组件,用于在后台执行长期运行的操作,而不需要与用户界面进行交互。它是Android四大组件之一
2. 声明周期
2.1. onCreate()
服务第一次启动创建时被调用,如果服务已经启动,再次使用startService或BindService ,不会触发该函数。
onBind
当其他组件想要通过bindService()来绑定服务时,系统调用该方法。如果你实现该方法,你需要返回IBinder对象来提供一个接口,以便客户来与服务通信。你必须实现该方法,如果你不允许绑定,则直接返回null。
onUnbind
当客户中断所有服务发布的特殊接口时,系统调用该方法。
onRebind()
当新的客户端与服务连接,且此前它已经通过onUnbind(Intent)通知断开连接时,系统调用该方法。
onStartCommand()
其他组件(如活动)通过调用startService()来请求启动服务时,系统调用该方法。如果你实现该方法,你有责任在工作完成时通过stopSelf()或者stopService()方法来停止服务。
每次调用startService都会被调用
返回值指示系统应具有的语义 用于服务的当前启动状态,默认情况下,要么返回START_STICKY_COMPATIBILITY ,要么返回START_STICKY
返回值取值范围:
-
START_STICKY_COMPATIBILITY
这是 START_NOT_STICKY 的一个旧版本,用于兼容较旧的 Android 版本。在较新的 Android 版本中,这个值的行为与 START_NOT_STICKY 相同。
-
START_STICKY
如果服务在启动后被系统杀死,那么系统会在稍后重新创建服务,并调用 onStartCommand() 方法。传递给 onStartCommand() 的 Intent 会是之前传递给服务的最后一个 Intent。这是最常见的返回值,用于那些即使服务在后台被杀死也需要尽快重启的服务。
-
START_NOT_STICKY
如果服务在启动后由于某种原因(如系统资源不足)被系统杀死,那么系统不会尝试重新创建服务。当用户再次启动应用或服务时,系统会调用 onStartCommand() 方法,但不会传递之前传递给服务的 Intent。
-
START_REDELIVER_INTENT
与 START_STICKY 类似,服务在启动后被系统杀死时会被重新创建。但是,传递给 onStartCommand() 的 Intent 会是之前传递给服务的 Intent,而不是最后一个 Intent。这通常用于那些需要处理每个启动请求的服务,即使服务在后台被杀死。
onDestroy()
当服务不再有用或者被销毁时,系统调用该方法。你的服务需要实现该方法来清理任何资源,如线程,已注册的监听器,接收器等。
3. 启动方式
3.1. startService()
启动服务,使用该方式启动服务如果服务不存在,则会创建服务并启动,如果存在服务onStartCommand函数会被回调
- Service不存在时Service生命周期:onCreate()-->onStartCommand()
- Service存在时Service声明周期:onStartCommand()
3.2. bindService
- public boolean bindService(@NonNull Intent service, @NonNull BindServiceFlags flags,@NonNull Executor executor, @NonNull ServiceConnection conn)
- public boolean bindService(Intent service, ServiceConnection conn,int flags)
- public boolean bindService(@NonNull Intent service, @NonNull ServiceConnection conn,@NonNull BindServiceFlags flags)
- public boolean bindService(Intent service, int flags, Executor executor,ServiceConnection conn)
参数说明:
- service:标识要连接的服务。Intent必须明确指定组件名称。该值不能为空。
- conn:在服务启动和停止时接收信息。这必须是一个有效的ServiceConnection对象;它不能为空。
- flags:操作项,有一下可选项:
- BIND_AUTO_CREATE
- BIND_DEBUG_UNBIND
- BIND_NOT_FOREGROUND
- BIND_ABOVE_CLIENT
- BIND_ALLOW_OOM_MANAGEMENT
- BIND_WAIVE_PRIORITY
- BIND_IMPORTANT
- BIND_ADJUST_WITH_ACTIVITY
- BIND_NOT_PERCEPTIBLE
- BIND_INCLUDE_CAPABILITIES
- executor:回调和侦听器事件通过这个Executor分派,提供了一种简单的方法来控制使用哪个线程。要通过应用程序的主线程调度事件,可以使用Context.getMainExecutor()。否则,提供一个Executor,将其分派到适当的线程。
3.2.1. bindService flasg参数
-
BIND_AUTO_CREATE
只要绑定存在,就自动创建服务,虽然这将创建服务,但它的service。onStartCommand(Intent, int, int)方法仍然只会因为显式调用startService(Intent)而被调用。尽管如此,在创建服务时,这仍然为您提供了对服务对象的访问。详细请参考:官方文档
-
BIND_DEBUG_UNBIND
当设置此标志时,将保留以下unbindService(ServiceConnection)调用的调用堆栈,以便在以后进行错误的unbind调用时打印。注意,这样做需要在应用的生命周期内保留绑定的信息,从而导致泄漏——这应该只用于调试。详细请参考:官方文档
-
BIND_NOT_FOREGROUND
不允许此绑定将目标服务的进程提升到前台调度优先级。它仍然会被提升到至少与客户端相同的内存优先级(这样在客户端不可杀死的任何情况下,它的进程都不会被杀死),但是出于CPU调度的目的,它可能会留在后台。这只有在绑定客户端是前台进程而目标服务在后台进程的情况下才有影响。
-
BIND_ABOVE_CLIENT
指示绑定到此服务的客户端应用程序认为该服务比应用程序本身更重要。详细请参考:官方文档
-
BIND_ALLOW_OOM_MANAGEMENT
允许承载绑定服务的进程进行正常的内存管理。详细请参考:官方文档
-
BIND_WAIVE_PRIORITY
不要影响目标服务的托管进程的调度或内存管理优先级详细请参考:官方文档
-
BIND_IMPORTANT
此服务对客户端非常重要,因此在客户端运行时应将其置于前台进程级别。详细请参考:官方文档
-
BIND_ADJUST_WITH_ACTIVITY
如果从一个活动绑定,允许目标服务的进程重要性根据该活动是否对用户可见而提高,而不管是否使用另一个标志来减少使用客户端进程的总体重要性来影响它的数量。详细请参考:官方文档
-
BIND_NOT_PERCEPTIBLE
如果绑定的应用程序是可见的或用户可感知的,那么将目标服务的重要性降低到可感知的级别以下。详细请参考:官方文档
-
BIND_INCLUDE_CAPABILITIES
如果绑定的应用程序由于其前台状态(如activity或前台服务)而具有特定的功能,那么该标志将允许被绑定的应用程序获得相同的功能,只要它也具有所需的权限。详细请参考:官方文档
3.3. startForegroundService
启动前台服务
详情请见前台服务
4. AndroidManifest.mxl 中配置
<service android:description="string resource"
android:directBootAware=["true" | "false"]
android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:foregroundServiceType=["camera" | "connectedDevice" |
"dataSync" | "health" | "location" |
"mediaPlayback" | "mediaProjection" |
"microphone" | "phoneCall" |
"remoteMessaging" | "shortService" |
"specialUse" | "systemExempted"]
android:icon="drawable resource"
android:isolatedProcess=["true" | "false"]
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string" >
...
<intent-filter>
<meta-data>
</service>
4.1. 标签说明
-
android:description
描述服务的用户可读字符串。此说明应设置为对字符串资源的引用,以便可以像界面中的其他字符串一样进行本地化。
-
android:directBootAware
确定服务是否可感知直接启动,也就是说,它是否可以在用户解锁设备之前运行。
默认值为 "false"。
-
android:enabled
确定系统是否可以实例化服务。如果可以实例化,则设为 "true",否则设为 "false"。默认值为 "true"。
<application> 元素具有自己的 enabled 属性,该属性适用于所有应用组件,包括服务。<application> 和 <service> 属性必须都设为 "true"(这正是它们两者的默认设置),才会启用服务。如果其中任一属性设为 "false",则表示服务已停用;无法对其进行实例化。
-
android:exported
确定其他应用的组件是否可以调用服务或与之交互。如果可以,则设为 "true",否则设为 "false"。当该值为 "false" 时,只有同一个应用或具有相同用户 ID 的应用的组件可以启动服务或绑定到服务。
默认值取决于服务是否包含 intent 过滤器。没有任何过滤器意味着该服务只能通过指定其确切的类名称进行调用。这意味着服务仅供应用内部使用,因为其他应用不知道其类名称。因此,在这种情况下,默认值为 "false"。 另一方面,如果存在至少一个过滤器,则意味着该服务会供外部使用,所以默认值为 "true"。此属性并非是唯一限制向其他应用披露服务的方式。您还可以使用权限来限制可以与服务交互的外部实体。请参阅 permission 属性。
-
android:foregroundServiceType
阐明服务是满足特定用例要求的前台服务。例如,"location" 类型的前台服务表示应用正在获取设备的当前位置,目的通常是继续用户发起的操作,且该操作与设备位置相关。
可以将多个前台服务类型分配给特定服务
-
android:icon
表示服务的图标。此属性应设置为对包含图片定义的可绘制资源的引用。如果未设置此属性,则改用为整个应用指定的图标。请参阅 <application> 元素的 icon 属性。
服务的图标(无论是在此处设置还是由 <application> 元素设置)也是服务的所有 intent 过滤器的默认图标。请参阅 <intent-filter> 元素的 icon 属性。
-
android:isolatedProcess
如果设置为 "true",则此服务会在与系统其余部分隔离的特殊进程下运行。此服务自身没有权限,唯一与其通信的方式是通过 Service API 进行绑定和启动。
-
android:label
服务的用户可读名称。如果未设置此属性,则改用整个应用的标签集。请参阅 <application> 元素的 label 属性。
服务的标签(无论是在此处设置还是由 <application> 元素设置)也是服务的所有 intent 过滤器的默认标签。请参阅 <intent-filter> 元素的 label 属性。此标签应设置为对字符串资源的引用,以便可以像界面中的其他字符串一样进行本地化。不过,为了方便您开发应用,也可以将其设为原始字符串。
-
android:name
实现服务的 Service 子类的名称。这是一个完全限定的类名称,例如 "com.example.project.RoomService"。不过,作为一种简写形式,如果名称的第一个字符是句点(例如 ".RoomService"),则会将其附加到 <manifest> 元素中指定的软件包名称。
发布应用后,除非您已设置 android:exported="false",否则请勿更改此名称。没有默认值。必须指定此名称。
-
android:permission
实体启动服务或绑定到服务所需的权限的名称。如果没有向 startService()、bindService() 或 stopService() 的调用方授予此权限,该方法将不起作用,且系统不会将 Intent 对象传送给服务。
如果未设置该属性,则对服务应用由\ <application> 元素的 permission 属性所设置的权限。如果二者均未设置,则服务不受权限保护。 -
android:process
运行服务的进程的名称。通常,应用的所有组件都会在为应用创建的默认进程中运行。它与应用软件包的名称相同。<application> 元素的 process 属性可以为所有组件设置不同的默认值。不过,组件可以使用自己的 process 属性替换默认属性,从而允许您跨多个进程分布应用。
如果为此属性分配的名称以英文冒号 (:) 开头,则系统会在需要时创建应用专用的新进程,并且服务会在该进程中运行。
如果进程名称以小写字符开头,则服务将在采用该名称的全局进程中运行,前提是它具有相应权限。这样,不同应用中的组件就可以共享进程,从而减少资源使用量。
评论区