Android之Services
【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()
系 统调这个方法当另一个组件,例如一个activity,请求启动这个service通过startService()。一旦这个方法执行,这个 service将启动并且无期限的运行在后台。如果你实现这个,那么停止service就是你的责任了当它的工作完成,通过调用stopSelf()或 stopService()。(如果你只希望提供绑定,你不需要实现这个方法)
onBind()
系 统调用这个方法当另一个组件希望绑定service(例如RPC),通过bindService()。在你这个方法的实现中,你必须提供一个客户使用的来 和这个service通信的接口,通过一个IBinder。你必须一直实现 这个函数,但如果你不希望允许绑定,那么你返回null。
onCreate()
系统调用这个方法当service第一次被创建,实现一次安装的步骤(在它调onStartCommand()和onBind()之前)。如果service已经在运行,那么这个方法不会调用。
onDestroy()
系统调用这个方法service不再使用将被摧毁。你的service应该实现这个来清理所有资源例如线程、注册的监听者、接收器等。这是service接收到的最后一个调用。
如果一个组件启动一个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
这是所有service的基类型。当你继承这个类,你新建一个线程来做service的工作就显得非常重要,因为这个service使用你应用程序的主线程,默认,这将降低你应用程序正在运行的所有activity的性能。
IntentService
这是一个Service人基类型,使用一个工作线程来操作所有开始的请求,一次一个。这是最佳选择如果你不需要你的service同时处理多个请求。所有你需要做的是实现 onHandleIntent(),接收intent从每个 开启的请求以便让你做后台工作。
【
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
如果系统杀死service在onStartCommand返回后,不要重新创建service,除非有等待的intent是发送。这是最安全的选项来避免运行你的service当不需要和当你的应用程序可以简单的重启任何未完成的工作。
START_STICKY
如 果系统杀死service在onStartCommand()返回后,重新创建service并且调用onStartCommand(),但不重发送 intent。相反,系统调用onStartCommand()用空intent,除非有等待的intent来启动service,在这种情况下,这些 intents被传送。这适合中级选手(或相似服务)不在执行命令,但运行无期限和等待一个工作。
START_REDELIVER_INTENT
如 果系统杀死service在onStartCommand()之后,重新创建service并且调用 用onStartComand()用最后一个intent,任何等待的intent都将被依次传递。这对一些service合适,它们常常活跃于处理一个 工作应该被立即恢复,就像下载一个文件。
【
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()。