一、什么是 Service?
Service 是一个可以在后台执行长时间任务而不提供用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可以绑定到服务,和它进行交互,甚至是执行进程间通信 (IPC)。例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。
注意:服务依赖于创建服务时所在的应用程序进程,默认是进程的主线程,它既不创建自己的线程,也不在单独的进程中运行(除非另行指定)。
这意味着,当某个应用程序进程被杀掉时,所有依赖于该进程的服务也会停止。
如果服务将执行任何 CPU 密集型工作或阻止性操作(例如 MP3 播放或联网),则应在服务内创建子线程来完成这项工作。
通过使用单独的线程,可以降低发生 “应用无响应”(ANR) 错误的风险,而应用的主线程仍可继续专注于运行用户与 Activity 之间的交互。
二、两种形式的服务
1. 启动服务
当应用组件(如 Activity)通过调用 startService() 启动服务时,服务即处于 “启动” 状态。一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响。已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。例如,它可能通过网络下载或上传文件。
2. 绑定服务
当应用组件通过调用 bindService() 绑定到服务时,服务即处于 “绑定” 状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
服务可以同时以这两种方式运行,也就是说,它既可以是启动服务(以无限期运行),也允许绑定。
问题只是在于是否实现了一组回调方法:onStartCommand()(允许组件启动服务)和 onBind()(允许绑定服务)。
任何应用组件均可像使用 Activity 那样通过调用 Intent 来使用服务(即使此服务来自另一应用)。不过,可以通过 AndroidManifest.xml 文件将服务声明为私有服务,并阻止其他应用访问。
三、什么时候使用服务,什么时候使用线程?
服务是一种即使用户未与应用交互也可在后台运行的组件。 因此,应仅在必要时才创建服务。
如果是在主线程外部执行工作,不过只是在用户正在与应用交互时才有此需要,则应创建新线程而非服务。 例如,如果只是想在 Activity 运行的同时播放一些音乐,则可在 onCreate() 中创建线程,在 onStart() 中启动线程,然后在 onStop() 中停止线程。当然还可以使用 AsyncTask 或 HandlerThread,而非传统的 Thread 类。
注意:服务在默认情况下是在应用的主线程中运行,因此,如果服务执行的是密集型或阻止性操作,则应在服务内创建新线程。
四、如何创建服务?
要创建服务,就必须创建 Service 的子类(或使用它的一个现有子类)。在实现中需要重写一些回调方法,包括:
1. onStartCommand()
当另一个组件(如 Activity)通过调用 startService() 请求启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。 如果实现此方法,则在服务工作完成后,需要主动调用 stopSelf() 或 stopService() 来停止服务。(如果你只想提供绑定,则无需实现此方法。)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
2. onBind()
当另一个组件想通过调用 bindService() 与服务绑定(例如执行 RPC)时,系统将调用此方法。在此方法的实现中,必须通过返回 IBinder 提供一个接口,供客户端用来与服务进行通信。请务必实现此方法,但如果你并不希望允许绑定,则应返回 null。
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
3. onCreate()
首次创建服务时,系统将调用此方法来执行一次性设置程序。在调用 onStartCommand() 或 onBind() 之前调用。如果服务已在运行,则不会调用此方法。
@Override
public void onCreate() {
super.onCreate();
}
4. onDestroy()
当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等。 这是服务接收的最后一个调用。
@Override
public void onDestroy() {
super.onDestroy();
}
两种方式创建服务
1. startService()
如果组件通过调用 startService() 启动服务(这会调用 onStartCommand() ),则服务将一直运行,直到服务使用 stopSelf() 自行停止运行,或由其他组件通过调用 stopService() 停止它为止。
Intent intent = new Intent(this, HelloService.class);
startService(intent);
2. bindService()
如果组件是通过调用 bindService() 来创建服务(不会调用 onStartCommand() ),则服务只会在该组件与其绑定时运行。一旦该服务与所有客户端之间的绑定全部取消,系统便会销毁它。
Intent intent = new Intent(this, HelloService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
五、什么时候系统会停止服务?
仅当内存过低且必须回收系统资源时,Android 系统才会强制停止服务。
如果将服务绑定到具有用户焦点的 Activity,则它不太可能会终止;
如果将服务声明为在前台运行,则它几乎永远不会终止。
如果服务已启动并要长时间运行,则系统会随着时间的推移降低服务在后台任务列表中的位置,而服务也将随之变得非常容易被终止;
如果服务是启动服务,则必须将其设计为能够妥善处理系统对它的重启。如果系统终止服务,那么一旦资源变得再次可用,系统便会重启服务(不过这还取决于从 onStartCommand() 返回的值)。
六、如何声明服务?
如同 Activity(以及其他组件)一样,必须在应用的清单文件中声明所有服务。要声明服务,请添加 <service> 元素作为 <application> 元素的子元素。例如:
<manifest ... >
...
<application ... >
<service android:name=".ExampleService" />
...
</application>
</manifest>
android:name 属性是唯一必需的属性,用于指定服务的类名。应用一旦发布,即不应更改此类名,不然,可能会存在因依赖显式 Intent 启动或绑定服务而破坏代码的风险。
为了确保应用的安全性,请始终使用显式 Intent 启动或绑定 Service,且不要为服务声明 Intent 过滤器。启动哪个服务存在一定的不确定性,而如果对这种不确定性的考量非常有必要,则可为服务提供 Intent 过滤器并从 Intent 中排除相应的组件名称,但随后必须使用 setPackage() 方法设置 Intent 的软件包,这样可以充分消除目标服务的不确定性。
此外,还可以通过添加 android:exported 属性并将其设置为 "false",确保服务仅适用于你的应用。这可以有效阻止其他应用启动你的服务,即便在使用显式 Intent 时也如此。
七、服务生命周期
服务的生命周期(从创建到销毁)根据服务类型不同而有两种路径:
1. 启动服务
该服务在其他组件调用 startService() 时创建,然后无限期运行,且必须通过调用 stopSelf() 来自行停止运行。此外,其他组件也可以通过调用 stopService() 来停止服务。服务停止后,系统会将其销毁。
2. 绑定服务
该服务在另一个组件(客户端)调用 bindService() 时创建。然后,客户端通过 IBinder 接口与服务进行通信。客户端可以通过调用 unbindService() 关闭连接。多个客户端可以绑定到相同服务,而且当所有绑定全部取消后,系统即会销毁该服务。(服务不必自行停止运行。)
这两条路径并非完全独立。也就是说,你可以绑定到已经使用 startService() 启动的服务。例如,可以通过使用 Intent(标识要播放的音乐)调用 startService() 来启动后台音乐服务。随后,用户可能需要控制播放器或获取有关当前播放歌曲的信息时,Activity 可以通过调用 bindService() 绑定到服务。在这种情况下,除非所有客户端均取消绑定,否则 stopService() 或 stopSelf() 不会实际停止服务。
八、实现生命周期回调
与 Activity 类似,服务也拥有生命周期回调方法,你可以实现这些方法来监控服务状态的变化并适时执行工作。 以下框架服务展示了每种生命周期方法:
public class ExampleService extends Service {
int mStartMode; // indicates how to behave if the service is killed
IBinder mBinder; // interface for clients that bind
boolean mAllowRebind; // indicates whether onRebind should be used
@Override
public void onCreate() {
// The service is being created
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// The service is starting, due to a call to startService()
return mStartMode;
}
@Override
public IBinder onBind(Intent intent) {
// A client is binding to the service with bindService()
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
// All clients have unbound with unbindService()
return mAllowRebind;
}
@Override
public void onRebind(Intent intent) {
// A client is binding to the service with bindService(),
// after onUnbind() has already been called
}
@Override
public void onDestroy() {
// The service is no longer used and is being destroyed
}
}
注意:与 Activity 生命周期回调方法不同,你不需要调用这些回调方法的超类实现。(IntentService 则需要确保调用超类实现,以便 IntentService 能够妥善处理工作线程的生命周期。)

左图显示了使用 startService() 所创建的服务的生命周期,右图显示了使用 bindService() 所创建的服务的生命周期。
通过实现这些方法,你可以监控服务生命周期的两个嵌套循环:
- 服务的整个生命周期从调用 onCreate() 开始起,到 onDestroy() 返回时结束。与 Activity 类似,服务也在 onCreate() 中完成初始设置,并在 onDestroy() 中释放所有剩余资源。例如,音乐播放服务可以在 onCreate() 中创建用于播放音乐的线程,然后在 onDestroy() 中停止该线程。
无论服务是通过 startService() 还是 bindService() 创建,都会为所有服务调用 onCreate() 和 onDestroy() 方法。
服务的有效生命周期从调用 onStartCommand() 或 onBind() 方法开始。每种方法均有 Intent 对象,该对象分别传递到 startService() 或 bindService()。
对于启动服务,有效生命周期与整个生命周期同时结束(即便是在 onStartCommand() 返回之后,服务仍然处于活动状态)。
对于绑定服务,有效生命周期在 onUnbind() 返回时结束。
不管启动方式如何,任何服务均有可能允许客户端与其绑定。因此,最初使用 onStartCommand()(通过客户端调用 startService() )启动的服务仍可接收对 onBind() 的调用(当客户端调用 bindService() 时)。
注意:尽管启动服务是通过调用 stopSelf() 或 stopService() 来停止,但是该服务并无相应的回调(没有 onStop() 回调)。因此,除非服务绑定到客户端,否则在服务停止时,系统会将其销毁 — onDestroy() 是接收到的唯一回调。