这一篇文章讲解service比较详细了, 需要不断用实际例子来消化它
【Services】
一个Service是一个应用程序组件,它能完成长时间运行的操作在后台,并且不提供用户接口。另一个应用程序组件能开启一个service并且它将继续运行在后台即使用户转换到另一个应用程序。额外的,一个组件可以被绑定到一个service来和它交互甚至完成进程间通信。例如,一个service可能操作网络带伤、播放音乐、执行I/O或和一个content provider交互,所有这些都是在后台进行。
一个service主要有两个用途:
1、Started
一个service被开启当一个应用程序组件(例如activity)用startService()开启它。一旦开启,一个service能无期限的运行在后台,即使创建它的组件被销毁。通常,一个启动的service完成一个单的操作,并且不返回结果给调用者。例如,它可能下载蔌上传一个文件通过网络。当操作完成,服务应该停止它自己。
2、Bound
一个service处于Bound状态,当一个应用程序组件绑定它通过bindService()。一个bound service提供一个客户端/服务器接口,以允许组件和service交互、发送请求、获取结果甚至做跨进程的进程间通信(IPC)。一个bound service运行只有当另一个应用程序组件绑定它。更多的是,组件能一旦绑定到service,但当它们所有都取消绑定,这个service就被摧毁。
虽然这篇文档主要单独地讨论两种不同类型的service,你的service可以两个都工作--它可以启动(无期限的运行)并且同样允许绑定。这只是你的组件是否实现了两个onStartComamnd()回调的问题,来允许组件启动它并且onBind()允许绑定。
不管你的应用程序是否启动、bound、或两个都是,任何一个应用程序组件都可以使用service(甚至从一个单独的应用程序),通过这种方式,任何组件能使用一个activity--通过一个Intent开启。可是,你能声明service私有,在manifest文件里,并且阻止访问从其它应用程序。
警告:一个service支它的主进程的主线程--service不创建它自己的线程并且不运行在单独的进程(除非你指定)。这意味着,如果你的service将要去做任何耗CPU的工作或阻塞操作(例如MP3播放或网络),你应该新建一个线程为这个service来完成那个工作。通过使用一个单独的线程,你将减少应用程序不响应(ANR)风险并且应用程序的主线程能专注于你的activity的用户交互。
【The Basics】
为了创建一个service,你必须创建一个service的子类(或已经存在类的子类)。在你的实现中,你需要需要覆盖一些回调函数,那些操作service生命周期关键方面并且给组件提供一个机制来绑定到serivce,如果合适。最重要的回调你应该覆盖的是:
onStartCommand()
onBind()
onCreate()
onDestroy()
如果一个组件启动一个service通过startService()(导致调用onStartCommand()),然后这个service维持运行直到它停止它自己通过stopSelf()或另一个组件停止它通过stopService()。
如果一个组件调用bindService()来创建service(onStartCommand()不被调用),那么这个service当组件绑定它的时候运行。一量service被取消绑定从客户,系统销毁它。
Android系统将强制停止一个service只有当内存很低并且它必须恢复系统资源为拥有用户焦点的activity。如果service绑定到一个拥有用户焦点的activity,那么它不太可能被杀,如果service被声明为运行在前台(稍后讨论),那么 它将几乎永远不会被杀。否则,如果service启动,并且一直运行,那么 系统会降低它的位置在后台任何列表里随着时间,并且service将变得高度被杀--如果你的service一年非常,那么你必须设计它温柔的被系统重启。如果系统杀死你的service,它重启它一量资源变得可利用(虽然这个也依赖于你从onStartCommand返回的值)。
【Declaring a service in the manifest】
像很多activities(以及其它组件),你必须声明所有的services在你的应用程序manifest文件里。
为了声明你的服务,加入<service>元素作为<application>元素的子元素。例如:
有其它的属性你可以在<service>元素中来定义属性,例如启动service的权限和service运行在哪一个进程。
就像一个activity,一个服务可以定义intent filters来允许其它组件激活服务使用隐含的intent。通过声明intent filters,任何其它应用程序的组件启动你的service如果你的service声明一个intent filter,匹配其它应用程序传递给startService()的intent。
如果你计划只本地使用你的service(其它应用程序看不见),那么你不需要(也不应该)提供任何intent filters。没有任何intent filters,你必须启动这个service使用一个intent,显式的命名service类。
额外的,你可以保证你的service是私有的对你的应用程序只有你包含android:exported属性并且设置它为"false"。这点非常有效,即使你的service提供intent filters。
【Creating a Started Service】
一个开启的service是由另一个组件调用startService()开启,导致调用service的onStartCommand()方法。
当一个service忘却,它有一个第一期周期独立于启动它的组件并且永远久运行在后台,即使创建它的组件被摧毁。这样,service应当停止它自己当工作完成通过stopSelf()函数,或另一个组件能停止它通过stopService()函数。
一个应用程序组件例如一个activity可以开启service通过startService()并且传递一个Intent指定了service并且包含任何数据给这个service来使用。Service接收这个Intent在onStartCommand()方法。
例如,假设一个activity需要保存一些数据给一个在线的数据库。这个activity可以启动一个伙伴service并且传递给它将要被保存的数据,通过传递一个intent给startService()。这个service接收intent在onStartCommand(),连接到网络,并且完成数据库事务。当事务完成,这个service停止它自己并且被摧毁。
警告:一个service运行在和应用程序的同一个进程的主线程,默认。所以,如果你的service完成高耗能或阻塞工作当用户和这个应用的activity交互的时候,这个service会减慢activity的性能。为了避免影响应用程序性能,你应该开始一个新线程在这个service中。
通常的,有两种类型你能继承来创建一个新service:
Service
IntentService
【
Extending the IntentService class】
因为大多忘却的services不需要同时操作多个请求(会有多线程场景问题),可能的最好的方法是如果你实现你的service使用IntentService类。
IntentService完成以下事情:
1、建立一个默认的工作线程执行所有的intent从onStartCommand()发来的,线程独立于你应用程序的主线程。
2、建立一个工作队列,一次传递一个intent给你的onHandleIntent()实现,这样你永远不用担心多线程。
3、停止service在所有的请求都处理完后,所以你永远不用调用stopSelf()。
4、提供默认的onBind()实现,即返回null的实现。
5、提供默认的onStartCommand()实现,发送intent给工作队列,然后发给你的onHandleIntent()实现。
所有这些加一起就是你所需要做的就是实现onHandleIntent()来完成你的工作。(虽然,你也需要提供一些构造函数为service)
下面是一个实现IntenService的例子:
这就是你所需要的:一个构造函数和一个onHandleIntent()的实现。
如果你也决定覆盖其它方法,例如onCreate()、onStartCommand()、或onDestroy(),保证调用父类实现,以便IntentService能合适的操作工作线程的生命期。
例如,onStartCommand()必须返回默认的实现(这决定intent怎样被送到onHandleIntent())
除了onHandleIntent()之外,惟一的方法你不需要调用的是onBind()(你只需要实现如果你的service允许绑定)。
【
Extending the Service class】
就像你在前面看到的,使用IntentService让你的启动service变得非常简单。可是如果,你要求你的service实现多线程行为(不能使工作线程工作),那么你可以继承自Service类来操作这个intent。
为了比较,下面的示例代码是一个Service的实现类,和上面的例子实现一样的功能使用IntentService。就是主产,对一个请求,它使用一个线程来袴工作并且一次只处理一个。
<!-- 此处图略,可从SDK文档中查阅 -->
你会发现,有更多的工作和使用IntentService相比。
可是,因为你操作每一个调用onStartCommand()你自己,你可以同时处理多个请求。这不是这个例子做的事情,但是如果你需要的话,那么你可以建立一个线程为每一个请求并且立即运行它们(而不是等待前一个完成)。
注意onStartCommand()必须返回一个整数。这个整数是一个值,描述系统怎么继续service当系统杀死它的时候(就像上面讨论的,IntentService默认帮你实现,虽然你能改变它)。从onStartCommand返回的值必须是下面中的一个:
START_NOT_STICKY
START_STICKY
START_REDELIVER_INTENT
【
Starting a Service】
你可以开始一个service从一个activity或其它应用程序组件通过传递一个Intent给startService()。Android系统调用这个service的onStartCommand()方法并且传递它Intent。(你应该从不调用onStartCommand()直接)。
例如,一个activity能启动示例service在前一节的(helloservice)使用一个显式 的intent用startService();
startService()方法立即返回并且Android系统调用service的onStartCommand()方法。如果service没有运行,系统调用onCreate(),然后调用onStartCommand()。
如果service也没有提供绑定,用startService()发送的intent是惟一的通信方法在组件和服务。可是,如果你希望service发送一个结果回去,那么客户开始这个service能创建一个PendingIntent为一个广播并且传递它给service。然后Service能利用广播来传送结果。
【
Stopping a service】
一个启动的service必须管理它自己的生命周期。也就是,这个系统不stop或摧毁除非系统要恢复内存,并且service一直运行在onStartCommand()返回后。这样,service必须停止它自己通过stopSelf或另一个组件可以停止它通过stopService()。
一旦请求停止用stopSelf或stopService(),系统摧毁这个service尽快。
可是,如果你的service在onStartCommand操作多个请求同时,那么 你不应该停止service当你已经完成一个请求,因为你可以已经接收到一个新的请求(在第一个请求后停止可能会终止第二个)。为了避免这个问题,你可以使用stopSelf(int)来确保你的请求停止总是基于最近的请求。也就是,当你调用用stopSelf(int),你传递ID关于当前请求(ID传递给onStartCommand)。那么如果service收到一个新的request在你能够调用stopSelf(int)之前,那么这个ID将不会匹配并且service将不会停止 。
警告:你的应用程序停止它的服务当它完成工作这点非常重要,为了避免浪费系统资源并且消耗电池。如果需要,其它组件可以停止service通过stopService()。即使你能绑定这个service,你必须一直停止这个service你自己如果它收到一个onStartCommand()。