在 Android 中,Service 主要有两种启动方式,分别是通过 startService() 方法启动和通过 bindService() 方法启动。
startService 和 bindService 启动服务的区别
| 区别 | startService | bindService |
|---|---|---|
| 生命周期的区别 | onCreate() -> onStartCommand()(onStart()方法已过时) -> onDestory() | onCreate() -> onBind() -> onUnbind() -> onDestory() |
| 运行的区别 | 一旦服务开启跟调用者(开启者)就没有任何关系了。 开启者退出了,开启者挂了,服务还在后台长期的运行。 | bind 的方式开启服务,绑定服务,调用者挂了,服务也会跟着挂掉。 |
| 是否可以调用服务里面的方法 | 开启者不能调用服务里面的方法。 | 绑定者可以调用服务里面的方法。 |
我们也可以同时使用 startService() 和 bindService() 来启动一个服务,这样服务既可以独立运行,又可以与启动组件进行交互。当需要停止服务时,需要同时调用 stopService() 和 unbindService()。
注意:多次 startService ,不会重复的执行 onCreate(), 而是会调用 onStart() 和onStartCommand();多次调用 bindService,不会执行任何生命周期方法。
startService 的启动流程
startService 的启动流程如上图所示。可以看到 startService 的启动流程 和 Activity 的启动流程其实差不多,区别主要是方式的调用。
下面介绍一下完整的调用逻辑:
- App 进程通过 ActivityManagerProxy 代理,调用到 AMS 的 startService 方法开启 Service 的启动流程
- AMS 的 startService 方法会检测 Service 进程是否存在。如果存在,会调用 realStartServiceLocked 直接执行图中的步骤 6、7、8;如果不存在,则会调用 startProcessLocked 方法启动进程(Activity 启动流程中,也是通过 startProcessLocked 创建进程的)
- zygote 通过 fork 创建 Service 进程,之后反射调用 ActivityThread.main 方法,再创建 ApplicationThread 与 AMS 通信。AMS 收到 ATTACH_APPLICATION_TRANSACTION 命令后,执行 attachApplicationLocked 方法,该方法会做两件事:1. 通过 ApplicationThreadProxy 回调 Service 进程,让其创建 Application;2. 调用 realStartServiceLocked 方法开始启动 Service。(该步骤中,除了 attachApplicationLocked 会启动 realStartServiceLocked 之外,其他流程都和 Activity 启动流程一样)
- realStartServiceLocked 方法会通过 ApplicationThreadProxy 发送 SCHEDULE_CREATE_SERVICE_TRANSACTION 命令。
- ApplicationThread 收到命令后,会发送消息 H.CREATE_SERVICE。Handle 收到该消息后,会调用 ActivityThread 的 handleCreateService 方法创建 Service。
bindService 的启动流程
bindService 的启动流程如上图所示。bindService 流程可以分为启动服务和绑定服务两步,其中启动服务流程和 startService 的流程一样,因此这里只介绍绑定的流程。
- App 进程通过 ActivityManagerProxy 代理,调用到 AMS 的 bindService 方法开启 Service 的绑定流程。其中 bindService 方法需要我们传入 LoadedApk 对象。该对象是 Apk 文件在内存中的表示。 Apk 文件的相关信息,诸如 Apk 文件的代码和资源,甚至代码里面的 Activity,Service 等组件的信息我们都可以通过此对象获取。
- 如果服务不存在,会通过 startService 来完成启动的流程
- 启动完成后,会调用 requestServiceBindingLocked,它会调用 ApplicationThreadProxy 的scheduleBindService 方法
- ApplicationThread 的 scheduleBindService 方法会发送消息 H.BIND_SERVICE。Handle 收到该消息后,会调用 ActivityThread 的 handleBindService 方法。
- 在handleBindService方法中,对未绑定服务的,先后调用Service的onBind方法和AMS的publishService方法;对已绑定服务的,先后调用Service的onRebind方法和AMS的serviceDoneExecuting方法。