A Service is an application component that can perform long-running operations in the background and does not provide a user interface.
Service 本质上有两种形态
Started,通过 startService 启动
Bound,服务可以绑定给 组件(bindService 是 Context 的方法)。服务提供 CS 接口给组件,组件通过接口与服务交流
两种形态可以同时工作,主要就是解决这个问题
Base
写一个服务需要这些基本的回调方法:
- onStartCommand(),组件通过 startService() 启动服务,系统就会调用这个方法(不过服务是否在运行,每次都会调用)。通过 stopSelf 和 stopService 来终止服务,单单使用 bound 形式的服务,无需实现这个方法。
- onBind(),当其他组件通过 bindService 来绑定到这个服务时,系统会调用这个方法。这个方法一定要实现,不过如果无需 bound 形式,那返回 null 就好。
- onCreate,服务创建时调用的方法(在 onStartCommand 和 onBind 之前调用,如果服务已经在运行,则不会再调用 onCreate)。不像 Activity,onCreate 不用先调用父方法。
- onDestroy,Activity 类似,调用这个方法意味着服务将被销毁,在这里释放资源
如果通过 start 启动服务,那服务只有调用 stopXXX 才会被终止。
如果通过 bounded 启动服务,那当没有组件绑定它的时候,系统将自动销毁它。
内存不足时,系统会杀死服务来释放资源:
- 普通服务(started 或 bounded 组件也在后台),运行越久越容易被杀
- bounded,只有绑定的 Activity 在前台 不容易被杀死
- setforeground,最不容易被杀死
!#TODO service 要考虑被被系统杀死和恢复
声明服务
<manifest ... >
...
<application ... >
<service android:name=".ExampleService" />
...
</application>
</manifest>
!#TODO 详细见 <service>
Started Service
Context#startService,实际上不是启动服务的命令,而是利用 Intent 向服务发送命令,是否启动服务由系统决定,调用者不知道这个方法是否会导致服务启动。应该理解为,向服务发送命令,这个命令可以是让服务开始做一件事,也可以让服务停止做一件事。甚至可以停用服务,这个取决于 Service#onStartCommand 的处理。 过时的 onStart 就是这样处理的,服务被系统杀死释放资源后,会重启只调用 onCreate 而没有 onStart,改进后会调用 onStartCommand 并传递 null intent,就是启动服务但不发送命令的意思。
记得只要服务和应用是在同一个进程执行的话,服务的生命周期方法都是在主线程执行的。
IntentService,是个方便的子类,提供 onHandleIntent 方法用於异步执行。
onStartCommand 的返回值用于告诉 Android 服务若被杀死后该怎么处理。几种不同 Start Id 的区别:
START_NOT_STICKY
不会重启
First run
07-23 22:06:37.033 15457-15457/? D/ServiceDemo﹕ onCreate
07-23 22:06:37.034 15457-15457/? D/ServiceDemo﹕ onStartCommand:1 flags:0
07-23 22:06:37.035 15457-15457/? D/ServiceDemo﹕ Dumping Intent start
Data:http://dourok.info/demo
Action:Test
[key=value]
Dumping Intent end
07-23 22:06:51.348 15457-15457/? D/Servi
killed
07-23 22:07:48.389 1157-1744/? W/ActivityManager﹕ Scheduling restart of crashed service info.dourok.android.demo/.services.ServiceDemo in 1000ms
START_STICKY
重启,但 Intent 为空
First run
07-23 22:01:03.369 10762-10762/? D/ServiceDemo﹕ onCreate
07-23 22:01:03.370 10762-10762/? D/ServiceDemo﹕ onStartCommand:1 flags:0
07-23 22:01:03.373 10762-10762/? D/ServiceDemo﹕ Dumping Intent start
Data:http://dourok.info/demo
Action:Test
[key=value]
Dumping Intent end
killed
07-23 22:02:16.695 1157-2100/? W/ActivityManager﹕ Scheduling restart of crashed service info.dourok.android.demo/.services.ServiceDemo in 1000ms
07-23 22:02:17.541 12814-12814/? D/ServiceDemo﹕ onCreate
07-23 22:02:17.541 12814-12814/? D/ServiceDemo﹕ onStartCommand:2 flags:0
07-23 22:02:17.547 12814-12814/? D/ServiceDemo﹕ null
START_REDELIVER_INTENT
重启,并返回上一次的 intent
First run
07-23 22:15:43.459 22569-22569/? D/ServiceDemo﹕ onCreate
07-23 22:15:43.460 22569-22569/? D/ServiceDemo﹕ onStartCommand:1 flags:0
07-23 22:15:43.461 22569-22569/? D/ServiceDemo﹕ Dumping Intent start
Data:http://dourok.info/demo
Action:Test
[key=value]
Dumping Intent end
killed
07-23 22:15:57.568 1157-2107/? W/ActivityManager﹕ Scheduling restart of crashed service info.dourok.android.demo/.services.ServiceDemo in 28518ms
07-23 22:16:26.141 1157-1207/? I/ActivityManager﹕ Start proc info.dourok.android.demo for service info.dourok.android.demo/.services.ServiceDemo: pid=23724 uid=10272 gids={50272, 9997} abi=armeabi-v7a
07-23 22:16:26.222 23724-23724/? D/ServiceDemo﹕ onCreate
07-23 22:16:26.222 23724-23724/? D/ServiceDemo﹕ onStartCommand:1 flags:1
07-23 22:16:26.225 23724-23724/? D/ServiceDemo﹕ Dumping Intent start
Data:http://dourok.info/demo
Action:Test
[key=value]
Dumping Intent end
IntentService 只有两种选择,不重启或重启并带回 Intent。
即便创建 Service 的 Activity 被销毁了,Service 还是运行着,即使 Service 不做任何事。多次运行 Activity Service#onStartCommand 也会被调用多次,但 onCreate 只有一次。重新运行程序,杀掉重启应用。服务也会重启的。这是 onStartCommand 会被调用两次,一次是系统重启,一次是 Activity 调用。
关于 flags:
- 0
- 1 START_FLAG_REDELIVERY 服务在调用 stopSelf 之前被杀掉,系统重启它将会带这个标志
- 2 START_FLAG_RETRY Intent 没有到达或没有 onStartCommand 没有返回,系统重新发送 Intent 将会带这个标志。onStartCommand 没有返回,Service 跟发送的组件不在同一个进程,才可能发送。我尝试在 onStartCommand 写个死循环并在新进程里运行服务。大约20秒左右,log 打出 Service 执行超时,然后居然死机,log 打出类似这样的。居然帮我找到 L50t 死机的原因。换另一台手机,大概一分钟后提示 ANR,然后强制关掉后,并没有重新启动服务。所以我也没办法重现找个标志了。
生命周期比 Activity 更简单:

回调
通过 Broadcast 回调
Bind Service
setForeground 避免被杀
回调
local ref
Message
startForeground
提升服务优先级到前台进程,前台进程最不容易被回收,Android将进程分为6个等级,它们按优先级顺序由高到低依次是:
- 前台进程( FOREGROUND_APP)
- 可视进程(VISIBLE_APP )
- 次要服务进程(SECONDARY_SERVER )
- 后台进程 (HIDDEN_APP)
- 内容供应节点(CONTENT_PROVIDER)
- 空进程(EMPTY_APP)
但是需要强制显示一个不可移除的通知