Android 复习_Service 一

来源:互联网 发布:tensorflow的api文档 编辑:程序博客网 时间:2024/04/29 12:30

 

服务Services

服务是一个应用组件,他可以在后台执行长时间的操作,并且不需要提供用户接口。别的应用组件可以启动一个服务,他将继续运行,即使用户已经切换到其它应用。此外,一个应用组件可以绑定到服务,并与之通信,甚至实现进程间通信(IPC)。例如:一个服务可能处理网络传输,播放音乐,执行文件的I/O处理,或者与contentprovider交互,所有都来自于后台。

一个服务基本上可以采取两种形式:

Started

当一个应用组件通过调过startService()启动了一个服务,服务便是”started”的了。一旦启动了,这个服务便可以在后台独立运行,即使启动他的组件已被销毁。通常,一个started的服务执行一个独立的操作,且不用给调用者返回结果。例如:他可能通过网络下载或者上载文件,完成之后自己停掉自己。

Bound

当应用组件通过bindService() 来绑定一个服务,这个服务便是“Bound”的了。一个绑定了的服务,提供了一个客户端到服务器的接口,他允许那个组件与服务通信,发送请求,接收结果,甚至跨进程间通信(IPC)。一个服务运行时间长度只与组件绑定他的时间长度一样。所有组件可以同时绑定他,但是当所有的组件都解除绑定关系,他就被销毁了。

你的服务可以以以上两种方式工作,是Started的也可以是Bound的。你实现一组回调是一件简单的事情,onStartCommand()允许你的应用组件去启动(start),onBind()允许你的应用组件去绑定(bind)他。

不论你的服务是Started的,Bound的,还是两者都实现了的,任何一个应用组件(甚至来自其它应用组件)都可以访问他,和访问Activity的其它组件的方式一样,用一个Intent来启动他。然而,你也可以声明一个服务是私有的,在manifest中,阻止来自其它应用的访问。

 

 基础(The Basics)

创建一个服务,你必须创建一个Service的子类(或者Serivce的子类的子类)。在你的实现中,你需要重载一些回调方法去处理服务生命周期关键的方面,如果适合,为组件提供一个绑定到服务的机制。你应该重载的最为重的一些回调方法如下:

onStartCommand():

当别的组件,如Activity,通过startService()请求这个服务启动时调用该方法。一旦这个方法执行了,服务就是Started的了,且他可以后台独立运行。如果你实现了这个方法,那么你有责任在他完成工作之后调用stopSelf()或者stopService()停止掉他。(如果你只想提供binding,你不需要实现这个方法)

onBind():

当别的应用组件想通过bindService()绑定到该服务时将调用这个方法(例如执行RPC)。在你的这个方法的实现中,你必须通过返回IBinder来提供一个客户端与服务器通信的接口。你通常实现这个方法,如果你不想被绑定,你可以返回一个null

onCreate():

系统第一次创建将调用这个方法,以执行一些一次性的设置工作(在执行onStartCommand()或者onBind()之前调用)。如果服务已经在运行了,他不会被调用。

onDestroy():

当服务不再被使用,且即将被销毁时调用此方法。服务实现这个方法是为了清理资源,例如:线程,注册了的listeners,广播接收者等等。这是服务接到的最后一个调用。

如果一个组件通过调用startService()来启动一个服务(onStartCommand()没有被调用),服务会保持运行到stopSelf()使其停止,或者别的组件通过调用stopService()使其停止。

如果组件通过bindService()来创建这个服务(onStartCommand()没有被调用),服务运行的寿命与绑定到他的寿命一样。一旦客户端unbind这个服务了,系统将会销毁他。

当处于低内存时,且持用用户焦点的Activity必须获取系统资源时,Android系统会强制关闭服务的。如果服务时被绑定到持有用户焦点的Activity时,他将不会优先被杀掉。如果服务被声明为runin foreground,他将永远不会被杀掉。否则,如果该服务已启动,并长期运行的,那么随着时间的推移系统会降低其在后台任务列表中的位置,该服务将变得非常容易杀,如果您的服务已启动,那么你必须设计,它优雅的处理由系统重新启动。如果系统杀掉你的服务,他会在资源再次可用时尽快重启。

 

manifest中声明服务(Declaring a service in the manifest)

 

Activity一样,你必须在你的应用中声明所有的服务。

声明一个服务,需要添加一个<service>元素作<application>元素的孩子。例如:

 

<service>元素中,还有一些其它的属性你可以包括用来定义他的一些属性,诸如启动服务的权限,服务应该在什么进程中运行。

Activity一样,一个服务可以定义intentfilters允许别个组件通过显式的intent来激活它。通过声明intentfilter,安装在同一个设备上的其它组件可以隐式的启动你的服务,如果你的服务声明的intent filter与别的应用传递给startService()intent相匹配。

如果你打算他你的服务仅在本地运行(别的应用不可以使用他),你不需要(也不应该)提供任务intentfilter。如果没有任何intentfilter,你必须要使用一个显示的服务的名称的intent来启动这个服务。

另外,你可以包含一个android:exported的属性,且设为false,这样可以确保你的服务只对你的应用私有。这即使是包括了intentfilter时也是有效的。

 

创建一个Started服务(Creating a Started Service)

 

一个started的服务是一个别的组件通过调用startService()来启动的服务,且最终有一个到到onStartCommand()方法的调用。

当一个服务是started的,他的生命周期独立于启动他的那个组件,他可以无限期的在后台运行,即使启动他的那个组件已被销毁了。所以,当他的工作完成了,服务应该调用stopSelf()来停止自己。或者由别的组件调用stopService()来停止。

一个应用组件如Activity可以通过调用startService()来启动这个服务,通过传递一个intent来指定这个服务,并且可以包含任何数据给这个服务使用。服务在onStartCommand()中接收这个Intent

照惯例,这里有两个类你可以扩展用以创建started的服务。

Service

这是所有服务的基类。当你扩展这个类,去创建一个新的线程来所有的服务的工作是很重要的,因为默认情况下,服务将使用应用的主线程,他可能会使你应用的正在运行的Activity的性能降低。

IntentService

这是一个service的子类,他使用一个工作者线程处理所有的请求,一次处理一个。如果你不要求你的服务同时处理多个请求,这是你最好的选择。你需要做的所有工作就是实现onHandleIntent()方法,他可以接收每个start请求的intent然后你可以开始后台的工作。

扩展IntentService(Extending the IntentService class)

由于大多数服务不需要同时处理多个请求,那么可能让你的服务实现IntentService类是最好不过的。

IntentService类实现如下工作:

·        创建一个默认的工作者线程,用来处理所有的传递给onStartCommand()intent,这个线程独立于你的主线程。

·        创建一个工作队列,一次向你的onHandleIntent()传递一个intent,所以你不必关心多线程工作方式。

·        在所有的启动请求完成之后停止服务,所以你不必调用stopSelf()

·        提供了一个默认的onBind()的实现,他返回null

·        提供了一个默认的onStartCommand()的实现,他发送intent到你的工作者队列,然后到你的onHandleIntent()的实现中。

所有这些都加起来得到这样一个事实,所有你需要做的是实现onHandleIntent()来完成客户端提供的工作。 (不过,你还需要为这个服务提供一个小构造。

这里有一个实现IntentService的例子:

 

 

你需要的所有是:一个构造函数和一个onHandleIntent()的实现。

如果你决定实现其它的回调方法,如onCreate(), onStartCommand(), onDestroy(), 需要确保要调用超类的实现,以确保IntentService能适当的处理工作线程的生命。

例如:onStartCommand()必须返回默认的实现(intent如何传递给onHandleIntent())



 

除了onHandleIntent(),从父类继承而来的只有onBind()不需要你调用超类的实现(如果你的服务允许绑定你只需实现你的内容)

扩展Service(Extending the Service class)

如果你的服务需要执行多线程,你需要继承service类来处理每一个intent

为了比较,下面的例子是从service扩展而来,执行着与以上使用IntentService完全一样的工作。为每个start的请求,他用一个工作者线程执行这个工作,并且每次只处理一个请求。

 


 

正如你看到的这样,他比使用intentService多做许多工作。

然而,由于你在你的onStartCommand()处理每一个调用,你可以同时执行多个请求。我们这个例子没有这样做,但是如果你想,你可以为每个请求创建一个新的线程,然后立即运行(而不是等待前面的请求完成)

注意到onStartCommand()必须返回一个整型。这个整型值描述了系统应该如何继续这个服务,或者杀死他(像上面讨论过的一样,IntentService的默认的实现帮你处理了这个,尽管你可以修改他)。onStartCommand()的返回值必须是以下值的其中之一:

START_NOT_STICKY

如果系统在onStartCommand()返回之后杀掉这个服务,将不会重新创建这个服务,除非这里有其它intent转递过来。这是最安全的选项,避免不必要的时候运行你的服务且当你的应用可以简单的启动任何没有完成的工作。

START_STICKY

如果系统在onStartCommand()返回之后杀掉这个服务,将重新创建服务,并且调用onStartCommand()方法,但是不会重新传递最后一个intent。相反,系统调用用一个nullintent调用onStartCommand(),除非这里有等等启动服务的intent存在,在这种情况下,那些Intent将会被传递。这适合媒体播放器(或类似的服务),不执行命令,但运行无限期等待合适的工作

START_REDELIVER_INTENT

如果系统在onStartCommand()返回之后杀掉这个服务,将重新创建服务,并且调用onStartCommand()方法,并将最后一个intent传递给他。任何挂起的意图依次交付。它适合于一个服务正在执行一项工作,他应该立即恢复工作,如下载一个文件

 

启动一个服务(Starting a Service)

你可以从一个Activity或者别的组件通过传递一个intentstartService()来启动一个服务。Android系统调用服务的onStartCommand()方法,并将intent传递给他(你永远不需要直接调用onStartCommand()方法)

例如:一个Activity可以使用显示的intentstartService()来启动前面的示例服务(HelloService)

 

 

startService()会立即返回,然后Android系统调 用服务的onStartCommand()方法。如果服务还没有运行,系统会首先调用onCreate(),然后再调用onStartCommand()

如果服务不提供绑定,在应用组件与服务之间唯一通信方式 就是将intent传递给startSerive()。然而,如果你想要你的服务发一个结果回来,客户端可以为一个广播( 使用getBroadCast())创建一个PendingIntent,在intent中传递给服务来启动服务。服务可以使用这个广播来传递这个结果。

许多请求去启动这个服务至使许多相应到onStartCommand()的调用。然而,只需要一个停止服务的请求(stopSelf()stopService())即可停止服务。

 

停止一个服务(Stopping a service)

一个启动了的服务必须管理好他的生命周期。系统不会停止会销毁这个服务回收系统内存除外,服务将在onStartCommand()结束后继续运行。所以服务必须自己通过调用stopSelf()来停止它或者别的应用组件过调用stopService()来停止他。

一旦通过stopSelf()或都stopService()调用来停止他,系统会尽快来销毁这个服务。

然而,如果你服务同时处理多个到onStartCommand()的请求,你不应该在处理完一个请求后便停止掉他,因为这时你可能刚刚接到一个新的请求(在第一个请求的最后阶段可能会终结前第二个请求)。为了避免这个问题,你可以使用stopSelf(int)来确保你的终止的请求总是基于最近的启动请求的。即是,当你调用stopSelf(int),你传递启动请求的ID(传递给onStartCommand()startId)到你停止请求的相适应。如果服务在可以接受stopSelf(int)之前接到一个新的启动请求,那个ID将不会匹配,且服务不会被停止掉。

注:当完成了他的工作之后,停止掉你的服务是很重要的,他可以避免浪费系统资源和耗费电池。如果有必要,别的组件可以通过调用stopService()来停止掉。即使你的服务是绑定的(binding),如果他也接受onStartCommand()的调用的话, 你也通常需要自己停止掉你的服务。

 

创建一个绑定的服务(Creating a Bound Service)

一个绑定的服务允许应用组件为了创建长时间的连接而通过调用bindService()来绑定到他( 并且通常不允许应用组件通过调用startService()来启动他 )

当你想让你的服务与Activity或者其它组件交互,或者暴露你的一些功能到其它应用,完成进程间通信,那么你应该创建一个绑定的服务。

创建一个绑定服务,你必须实现onBind()方法来返回一个IBinder,这个接口定义与如何与该服务通信。别的组件可以通过调用bindService()来个获取这个接口,并且开始调用服务的其它方法。服务只为绑定到他的应用组件服务,所以当没有组件绑定到服务时,系统会销毁他。

创建一个绑定服务,第一件事是定义一个接口,指定客户端可以怎样与服务端通信。服务端与客户端之间的接口必须是一个IBinder的实现,并且由你的onBind()方法返回。一旦客户端获得了IBinder,他可以通过这个接口与该服务进行交互。

可以同时有多个客户端绑定到这个服务。一旦一个客户端完成了与该服务的交互,调用unBind()来解除这种绑定关系。一旦没有客户端绑定到该服务,那么系统就会销毁掉该服务。

 

给用户发通知(Sending Notifications to the User)

一旦运行了,一个服务可以通过ToastNotifications或者StatusBar Notifications来给用户发通知。

一个Toast通知是在当前的窗口上显示一个消息,过会儿便消失。一个statusbar 的通知是在statusbar中提供一个图标和一则消息,用户可以选中他从而发生一个动作,比如启动一个Activity

通常,当一个后台工作完成了(例如下载文件完成了),用户可以在他上面作一些行动,此时最好的技术使用StatusBar Notifications。当用户从扩展视图中选择这个通知时,那个通知可以启动一个Activity(例如去显示已下载文件)

在前台运行一个服务(Running a Service in the Foreground)

一个前台服务被认为用户正在关注的某事,并且不会在低内存情况下作为杀死的候选。一个前台服务必须给StatusBar提供一个通知,他用来放置“正在进行”的标题,它意味着,这个通知不能被清除除非这个服务被停掉了,或者从前台移掉了。

例如,一个音乐播放器从服务播放音乐,应该被设置为在前台运行,因为用户明确的知道他的操作。通知可能用来指示正在播放的歌曲,并且允许用户启动一个Activity来与音乐播放器交互。

为了让你的服务在前台运行,需要调用startForeground()。这个方法需要两个参数:一个作为该通知的唯一标识的整数,以及一个给StatusBar提供的Notification。例如:

 


 

要从前台移除服务,需要调用stopForeground()。这个方法需要一个boolean参数,用以指定是否也同时移除掉StatusBar的通知。这个方法并不停止掉这个服务。然而,如果你停止掉你的服务,而他正在前台运行,StatusBar的通知会被移动掉。

 

管理服务的生命周期(Managing the Lifecycle of a Service)

服务的生命周期比Activity的要简单的多。然而,更重要的是你要密切注意你的服务是如何创建和销毁的,因为服务可以在后台运行,而不被用户察觉。

服务的生命周期,从他创建到销毁,可以遵循两种不同的路径:

·        一个启动地服务(A Started Service)

当别的组件调用startService()时创建该服务。然后服务独立的运行,并且必须要通过调用stopService()来停止他。别的组件也可以通过stopService()来停止他。当服务停止了,系统便销毁他。

·        一个绑定服务(A Bound Service)

当别的组件(客户端)调用bindService()时,该服务创建了。客户端通过一个IBinder的接口来与该服务通信。客户端可以通过unBindService()来关闭这个连接。多个客户端可以绑定到同一个服务,当所有的客户端解除绑定了,系统才销毁这个服务。(服务不需要停止他自己)

这两种路径不是完全独立的。即是说,你可以绑定个通过startService()启动了的服务。例如:一个后台的音乐服务可以通过startService()来启动,他用一个intent来识别那个播放的音乐。稍后,用户可能对播放器作一些控制,或者查看正在播放的歌曲的信息,一个Activity可能通过bindService()绑定到这个服务。在这种情况下,stopService()或者stopSelf()在所有的客户端解除绑定之前并不能实际停止掉这个服务。

实现生命周期的回调(Implementing the lifecycle callbacks)

Activity一样,服务也有生命周期回调方法,你可以实现这些回调方法以监视服务状态的改变,在适当的时候做出相应的工作。下面的骨架演示了生命周期的每一个方法:

 


注:不像Activity的生命周期的回调方法,不要求在你的生命周期回调方法中调用超类的相应方法。

通过实现这些方法,可以监视生命周期的两个嵌套的循环:

·        onCreate()onDestroy()整个生命期(entire lifetime)。像Activity一样,服务在onCreate()中做一些初始化的工作在onDestroy()中释放掉其所持有的资源。

所有的服务都调用onCreate()onDestroy(),不论你的服务是通过startService()创建还是bindService()创建。

·        活动生命期(activelifetime),当一个服务被onStartCommand()或者onBind()调用开始。每个方法都处理了通过startSerice()或者bindService()传递给他的intent

如果服务是started的,活动期的结束即是整个生命期的结束(即使在onStartCommand()结束之后仍然是活动的)。如果服务是绑定的,那么活动期会在onUnbind()之后结束。

注:尽管一个服务是通过stopSelf()或者stopService()来停止的,但是服务没有一个独立的回调(没有onStop()的回调)。所以,如果服务没有被绑定到一个客户端,当服务停止了系统将会销毁他,onDestroy()是唯一接到的回调。