IntentService 是 Service 的子类,当然也是用于处理耗时操作的,通过 startService(Intent) 启动,并且会在工作线程中处理每个 Intent,并在操作结束或不正常时自行停止。
要看懂 IntentService 的源码,必须熟悉 Handler 机制,不明白的建议先了解一下 Handler 机制。
IntentService 的用法
要使用 IntentService,只需要创建一个类继承 IntentService 并实现抽象方法 onHandleIntent(Intent)。
1 | public class InitializeService extends IntentService { |
就这么简单,我们只需要把精力用在重写 onHandleIntent 方法处理耗时操作就可以了,也不用开启新的线程。
而如果直接使用 Service,恐怕就没那么简单了,我们需要处理很多事情,比如耗时操作要单独创建一个工作线程,操作结束后要停止 Service 运行等等。
那么 IntentService 是怎么实现将 Service 中复杂的逻辑简化为只需要实现一个 onHandleIntent 方法就可以的呢?
其实 IntentService 是通过对 Service 的各个生命周期进行处理,并结合了 Android 中强大的 Handler 机制来完成的。
下面就根据 Service 的生命周期,分析 IntentService 的实现原理。
先借用 Android 官网的 Service 生命周期图看一下:
下面以通过 startService 启动 IntentService 为例,进行分析。
OnCreate
下面是 IntentService 的 onCreate 方法的源码:
IntentService.java
1 | private volatile Looper mServiceLooper; |
创建一个 HandlerThread,也就是一个子线程,并启动这个线程。获取这个线程绑定的 Looper,再利用这个 Looper 创建一个 Handler,因为这个 Looper 是与 HandlerThread(一个新的工作线程)绑定的,所以与这个 Looper 关联的 Handler 也就在 HandlerThread 线程中接收与处理消息。
HandlerThread 启动后,必然会运行 run() 方法,接下来看一下 HandlerThread.run()。
HandlerThread.java
1 | /** |
当 HandlerThread 启动后,在 run 方法中会调用 Looper.prepare() 方法创建 Looper 的实例并与 HandlerThread 线程相关联,然后调用 Looper.loop() 方法开始循环处理消息。
onStartCommand/onStart
1 |
|
onStartCommand 方法内部会调用 onStart 方法,onStart 方法中就是创建一个 Message 对象,并把 Intent 和 startId 保存到这个 Message 对象中,最后通过 mServiceHandler 发送消息。
1 | private final class ServiceHandler extends Handler { |
因为 ServiceHandler 是在子线程中接收消息,所以handleMessage() 方法自然也就在子线程中处理,onHandleIntent() 同样如此,最后处理结束后调用 stopSelf 方法停止 Service 运行。
为什么当有多个任务时 hanndleMessage 中 stopSelf(msg.arg1) 不会终止 Service?
因为在 onStartCommand 中会传入一个 startId,这个 startId 保存在 msg.arg1 中,因此每次调用 startService() 都会回调这个方法,所以每个 startId 也就不同,
也就是说,每当我们调用startService()启动一个服务时,不但会在其对应的 ServiceRecord 节点的 pendingStarts 里插入一个新的 StartItem 节点,而且会为这个 StartItem 节点生成一个新的 id 号,这个 id 号就是日后的 startId(生成id号时,采用的办法是最简单的加1操作)。
而在 stopSelf() 中传入的也是这个 startId,所以在关闭时,会关闭这个 startId 指定的任务,同时会判断是否是最后一个 startId,如果是最后一个才真正的结束 Service,否则不结束。
也就是按序从 ServiceRecord 的 deliveredStarts 列表中删除 StartItem 节点,直到所删除的是 startId 参数对应的 StartItem 节点,如果此时尚未抵达 ServiceRecord 内部记录的最后一个 start Id 时,则说明此次 stopSelf()操作没必要进一步结束service,那么直接 return false 就可以了。只有在所删除的 startItem 节点的确是最后一个 startItem 节点时,才会调用 bringDownServiceIfNeededLocked() 去结束 service。这就是为什么 IntentService 的 ServiceHandler 在处理完消息后,可以放心调用 stopSelf() 的原因。
onDestroy
1 |
|
当 Service 真正停止时会回调 onDestroy() ,这时 mServiceLooper 会退出循环。
IntentService VS Service
运行线程 | 结束 | |
---|---|---|
IntentService | 自动创建工作线程处理任务 | 自动结束,不需要处理。 |
Service | 主线程 不能处理耗时操作,需编写代码创建子线程。 |
需要主动调用stopService() |
IntentService VS 普通线程
线程优先级 | |
---|---|
IntentService | 高 不容易被系统杀死 |
普通线程 | 低 若进程中无活动的四大组件,则该线程的优先级非常低,容易被系统杀死。 |