【Android】17.1 Bound Services基本概念

分类:C#、Android、VS2015;

创建日期:2016-03-03

一、Bound Services—被绑定的服务

1、什么是Bound Service

Bound Service是指通过接口将Android的组件(比如某个Activity)和某个Service绑定在一起,这是一种类似于C/S的通信机制,组件Activity是客户端(调用服务),Service是服务端(提供服务)。

一旦定义了客户端和服务之间绑定的接口,客户端就可以利用该接口向服务端发送服务请求,并接收服务端响应的结果。另外,利用消息传递机制,还可以实现不同进程之间的通信(IPC)。

Bound Services与Started Service的主要区别是:Bound Services中的Service不会无限期地在后台持续运行(客户端建立连接时创建服务,客户端断开连接时销毁服务),而Started Service中的Service则可以无限期地在后台持续运行。

一旦将客户端的Activity和服务端的Service绑定在一起,这种被绑定的Service就有了自己的生命周期。

2、Bound Services的生命周期

下图说明了Bound Services的生命周期以及自动调用的方法。

image

从图中可以看出,在Bound Service的完整生存期期间,也是开始时调用OnCreate()方法,结束时调用OnDestroy()方法。与activity类似,服务可以在重写(override)的OnCreate()方法中完成初始设置工作,并在重写的OnDestroy()方法中释放所有未释放的资源。例如,一个音乐播放服务可以在OnCreate()中创建音乐播放线程,而在OnDestroy()中终止该线程。

总之,只要将客户端和服务绑定在一起,不论是用StartService()创建的服务(Started Service),还是用BindService()创建的服务,这些服务都会调用OnCreate()和OnDestroy()方法。

在这些回调方法中,最常用的是OnBind()和OnUnBind(),含义如下:

  • OnBind()方法:用于返回绑定的实例,当客户端与服务建立绑定时系统会自动调用此方法,然后客户端就可以通过该方法返回的实例访问服务了。
  • OnUnbind()方法:当客户端取消与服务的绑定时系统会自动调用此方法。如果该方法返回true,表示该服务可被重新绑定;否则(返回false)表示该方法什么事都没做。

二、Bound Service和Started Service的区别

从Bound Service的生命周期可以看出,在Service的生命周期管理中,Bound Service与Started Service明显不同。

这些区别有:

1、创建和销毁的方式不同

Started Service由其它组件调用StartService()方法来创建,然后该Service就可以保持运行了,而且必须通过它自己调用StopSelf()终止自身或者其它组件通过调用StopService()来终止它。服务终止后,系统会自动把它销毁;而Bound Service则是由其它组件(客户端)调用BindService()来建立连接,然后客户端通过一个IBinder接口与服务进行通信,通过调用UnbindService()关闭连接。另外,多个客户端可以绑定到同一个服务上,当所有的客户端都解除绑定后,系统才会销毁服务。

但是,Bound Service和Started Service并不是完全隔离的。也就是说,你也可以绑定到一个已经用StartService()启动的服务上。例如,你可以通过调用StartService()方法来启动一个后台音乐服务,传入一个指明所需播放音乐的Intent。 之后,用户也许需要用播放器进行一些控制,或者查看当前歌曲的信息,这时其他的activity可以通过调用BindService()与此服务进行绑定。在类似这样的情况下,即使你调用了StopService()方法或者StopSelf()方法,也不会真的终止被绑定的服务,除非所有的客户端都解除了绑定。

本章的例17-2通过具体代码演示了如何绑定到Started Service。

2、活跃生存期不同

Service的活跃生存期开始于OnStartCommand()或OnBind()的调用。这两个方法分别会传给StartService()或BindService()的Intent。如果服务是Started Service,则它的活跃生存期与完整生存期同时结束(即使OnStartCommand()返回后服务仍然处于活跃期)。如果服务是Bound Service,则活跃生存期在OnUnbind()返回后结束。

注意:虽然Started Service是通过它自己调用StopSelf()或通过其他组件调用StopService()来终止的,但是服务却没有提供类似OnStop()的回调方法。因此,除非将服务与客户端绑定在一起,否则系统就会在服务终止时销毁它。或者说,OnDestroy()是服务唯一会收到的回调方法。

image

 

上图标明了服务中典型的回调方法。尽管此图把StartService()创建的服务和BindService()创建的服务分开描述了,但请记住,无论启动方式如何,所有的服务实际上都允许被绑定。因此,对于通过OnStartCommand()启动的服务(客户端调用StartService()启动它),当客户端又调用了BindService()方法时,仍然可以接收OnBind()返回的结果,而这个返回的结果就是通过IBinder接口来实现的。

三、实现IBinder接口的方式

实现Bound Service的方式有多种,实现过程也比实现Started Service要复杂一些。

为了让Service支持绑定,服务必须实现OnBind()回调方法。这个方法返回一个IBinder对象,此对象定义了客户端与服务进行交互时所需的编程接口。

在服务中定义IBinder接口的方式有三种。

1、在继承自Binder的类中实现接口

如果你的服务只是为你自己的应用程序执行一些后台工作,此时,在继承自Binder的类中实现接口是首选的技术方案。不使用这种首选技术方案的理由只有一个:就是被绑定的服务可能还要被其它应用程序使用或者需要跨多个进程使用。

具体用法见本章的例17-1、例17-2、例17-3。

2、用Messenger实现接口

当应用程序中的activity或其它组件需要与Service进行交互,或者应用程序中的某些功能需要暴露给其它的应用程序时,此时首选的方案就是创建一个Bound Service,并通过进程间通信(IPC)来完成应用程序之间的消息传递。

如果你实现的接口需要跨越多个进程进行工作(比如实现两个进程A和B之间的通信,将消息从B发送到A),可以通过Messenger来为服务创建接口。在这种方式下,A进程中的服务定义一个响应各类消息对象Message的Handler,此Handler是Messenger与客户端(进程B)共享同一个IBinder的基础,它使客户端(进程B)可以用消息对象Message向服务(进程A)发送指令。此外,客户端还可以定义自己的Message,以便服务能够回发消息。

这种方式是执行进程间通信(IPC)最简便的方式,因为Messenger会把所有的请求放入一个独立进程中的队列,这样你就不一定非要把服务设计为线程安全的模式了。

具体用法见本章的例17-4。

3、用AIDL实现接口

AIDL(Android Interface Definition Language,Android接口定义语言)完成以下的所有工作:一是将对象解析为操作系统可识别的原始形态,二是将它们跨进程序列化(marshal)以完成进程间通信(IPC)。

当需要进程间通信(IPC)时,用Messenger实现要比用AIDL实现容易些,因为Messenger会把所有调用服务的请求都放入到一个队列中。而AIDL会把这些请求同时发送给服务,这样服务就必须多线程运行才能及时响应请求。

实际上,Messenger本质上也是基于AIDL的,只不过它仅在一个单独的进程中创建了一个队列,所有客户端请求都先进入该队列然后再依次取出来进行处理,这样服务每次就只会收到一个请求。可是,如果想让你的服务能“同时”处理多个请求,你可以直接用AIDL来实现。这种情况下,一定要确保你的服务必须拥有多线程处理的能力,并且是以线程安全的方式编写的。

总之,对经验不足的编程人员而言,实现进程间通信首选的办法就是用Messenger来实现,这样虽然运行效率低一些,但是不容易出错。而直接用AIDL实现虽然效率很高而且也很灵活,但是这需要有非常丰富的编程经验才能得心应手。这就像开汽车,不是简单学一学怎样把车开走就意味着也能立即会“玩漂移”的,如果你觉得自己对多线程把握不好或者编程经验不老道,最好还是别去招惹AIDL。

如果你的服务需要与远程进程进行通信,你同样可以使用一个Messenger来提供服务的接口。这种技术能让你无需使用AIDL就能实现进程间通信(IPC)。

posted @ 2016-03-03 09:03  rainmj  阅读(705)  评论(0编辑  收藏  举报