Android开发笔记(五)- Service组件
在Android开发笔记之基础篇(二)中,我们简单总结了Activity组件的特性和使用方法。在其之后的第二个重要组件就是Service(服务)。简单来说,如果说Activity是负责处理与用户交互的UI部分的内容,那么Service则是负责在后台处理一些长时间,大型的操作或计算的内容。今天我们就继续来看看Service组件的特性以及使用方法。
Service
首先,在Google doc官方说明文档中对Service的解释是:
A
Service
is an application component that can perform long-running operations in the background. It does not provide a user interface.
所以从这里我们可以很清晰的看到Service的两个特性:后台运行和长时间运行。适合使用Service的场景实例有很多,比如播放音乐或者进行网络文件下载,与ContentProvider进行交互等等。在某些情况下,即使App被关闭后,其开启的Service依旧能够在后台运行。
Service分类
按照不同的分类方式,Service可以从运行地点,运行类型以及功能进行分类:
运行地点
本地服务(local service)
:运行在主线程(main thread),受线程的控制,主线程终止时,其也会被终止;远程服务(remote service)
:运行在自己的独立线程,常驻后台,不被其他activity影响,但会消耗更多资源。
运行类型
前台服务(Forground)
:所谓“前台”,是指其会在通知栏中显示出来,需要让用户看到,并且终止时通知也会消失;后台服务(Background)
:不会显示在通知栏,用户无法知晓是否仍在运行。
功能
不可通信
:使用startService()
直接开启,调用者退出后,该service可继续存在,不可与调用者(例如activity)进行通信;可通信
:使用bindService()
绑定开启,调用者退出后,该service也会退出并销毁,可以与调用者(例如activity)进行通信。
生命周期 Service lifecycle
启动一个Service主要有两种方式:startService()
直接开启 或 bindService()
绑定开启,两种方式产生的Service的生命周期不完全相同。先放上Google doc官方文档中给出的说明图:
这里我们首先需要知道,在Service
中有四个手动调用的方法:startService()
, stopService()
, bindService()
和unbindService()
,通过手动调用这四个方法,可以使其自动调用另外五个方法:onCreate()
, onStartCommand()
, onBind()
, onDestory()
和onUnbind()
。所以下面我们就对四个需手动调用的方法来一一详细分析其在Service生命周期中的使用方法和规律:
startService()
startService()
会直接启动Service服务,即使多次手动调用startService()
只会调用一次onCreate(), 但会多次调用onStartCommand(),onStartCommand()
的调用次数和startService()
保持一致,也只有onStartCommand()可以被多次自动调用。- 当
onStartCommand()
被自动调用时,会返回一个整数flag,其用于表示当该Service被系统销毁时要如何处理,这个flag有三种可能的状态:1.START_NOT_STICKY
:除非还存在未发送的intent,否则该Service不会被重建;2.START_STICKY
: 重建服务,但不会再次发送最近一次已发送的intent,适用于例如媒体播放等需要持续待命,但不用立刻运行的场景;3.START_REDELIVER_STICKY
: 重建服务并发送最近一次已发送的intent,适用于例如文件下载等需要立刻恢复运行的场景; - 当返回的flag是
START_STICKY
或START_REDELIVER_STICKY
时,onStartCommand()
也会被重新调用。
stopService()
stopService()
会直接关闭Service服务,但需要注意的是:在已经绑定服务(调用过bindService()
)之后如果没有解绑,stopService()
是不会关闭服务的。
bindService()
- 即使多次手动调用
bindService()
,实际上onCreate()
也只会被调用一次,即只存在一个Service实例; - 当一个服务已经通过
startService()
直接启动之后,依旧可以通过bindService()
来绑定服务并使用。
unbindService()
- 如果使用
bindService()
绑定启动服务,那么 - 当多个客户端(client)绑定到同一个Service服务时,系统会在所有的客户端都解绑之后自动销毁服务,不需要手动调用
unbindService()
。
题目练习
不妨用以下的test case来测试一下上面的流程图是否已经掌握,通过手动调用方法的顺序来判断Service自动调用方法的顺序:
Service VS IntentService
Service
与IntentService
的区别是一个非常常见的面试题目,其主要区别包括:
IntentService
是Service
的一个子类,主要通过一个work queue来处理从客户端接收到的intent,适用于处理较长时间的任务;Service
运行在主线程(main thread),无法处理耗时任务,否则主线程阻塞会出现ANR,而IntentService
可以在独立的子线程上运行;Service
可以从任何线程上启动,而IntentService
只能从主线程上启动;Service
通过手动调用startService()
或bindService()
来开启服务,而IntentService
需通过Context.startService(Intent)
来开启服务;Service
通过手动调用stopService()
来停止并销毁服务。但IntentService
会在所有intent被处理完之后自动停止;IntentService
会自动调用onBind()
方法并返回一个null值,并为onStartCommand()
提供了默认实现,将请求的intent添加进队列中。
参考文章
Google Document: Services overview