Android 复习_Service 二

来源:互联网 发布:有点牛网络公司 知乎 编辑:程序博客网 时间:2024/05/19 13:23

Bound Services

一个绑定的服务是一个客户端之间的接口的服务。一个绑定的服务器允许组件(比如Activity)绑定到这个服务,发送请求,接收响应,甚至执行进程间通信。一个绑定的服务典型的是只当他为别的组件服务时才是活动的,他不会在后台单独运行。

 

基础知识(The Basics)

一个绑定的服务是一个Service类的一个实现,他允许别的应用绑定到他,并且与他交互。一个服务要实现绑定功能,你必须实现onBind()回调方法。这个方法返回一个IBinder的对象,他定义了客户端可以用来与服务相交互的接口。

一个客户端可以通过bindService()绑定到这个服务。当他这样做的时候,他们必须提供一个ServiceConnection的实现,用他来监视与该服务的连接。bindService()会立即返回,且而任何返回值。但是当Android系统创建客户端与服务端的连接时,他会调用ServiceConnectiononServiceConnected()方法,并且给他传递IBinder对象,客户端可以用他来与服务端进行通信。

多个客户端可以同时绑定到这个服务。然而,系统只在第一次客户端绑定到该服务时调用该服务的onBind()方法去得到IBinder。系统将传递相同的IBinder到任何其它的绑定到该服务的客户端,而不是再调用onBind()一次。

当最后一个客户端解除了与服务的绑定,系统将销毁掉这个服务。(如果该服务也被startService()启动除外。)

当你实现你的绑定的服务时,最重要的工作是定义你的onBind()方法返回的接口。

 

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

当创建一个服务,提供绑定功能,你必须提供一个IBinder作为与客户端进行交互的接口。这里有三种方法你可以用来定义这个接口。

扩展Binder(Extendingthe Binder Class)

如果你的服务对于你的应用而言是私有的并且与这个客户端运行在同一个进程中(这是一种很常见的),你应该通过扩展Binder来创建你的接口,并通过onBind()来返回这个接口。客户端得到Binder,并且可以直接该问他的公有方法,甚至服务的公有方法。

当服务仅仅作为你自己应用中后台运行的一部分时,使用这个技术是比较好的选择。唯一不应该使用这种方法的理由是,你的服务可能会被其它应用使用,或者从不同的进程访问。

使用Messenger(UsingMessenger)

如果你的服务需要跨进程工作,你可以使用Messenger为你的服务创建一个接口。这种方式下,服务定义一个Handler,他来响应不同类型的Message对象。这个HandlerMessenger的一个基础,他可以给客户端分享一个IBinder,他允许客户端使用Message对象向该服务发命令。另外,客户端可以为自己定义一个Messenger,这样服务端可以发消息回来。

这是一种进程间通信(IPC)的最简单的方式。由于Messenger将所有的请求排好队放入一个单独的线程,所以你永远不需要设计你的服务为线程安全。

使用AIDL(UsingAIDL)

AIDL(Android Interface DefinitionLanguage) 执行所有的工作来将对象分解为操作系统可以理解的原始状态并调整它们来跨线程执行IPC。前面的技术,使用Messenger,实际上是基于AIDL作为基础架构的。像前面提到的那样,Messenger一个单独的线程中为所有的客户端的请求创建一个队列,所以一次只得到一个请求。然而,如果你想要你的服务同时处理多个请求,你可以直接使用AIDL。这种情况下,你的服务必须具备多线程能力,并且要考虑线程安全。

直接使用AIDL,你必须定义一个.aidl文件来定义编程接口。AndroidSDK工具用这个文件去生成一个抽象类,他来实现接口和处理IPC,这些可以在你的服务中被扩展。

注:绝大多数应用都不应该使用AIDL来创建绑定服务,因为他需要多线程能力,且使其实现复习化。

扩展Binder(Extending theBinder class)

如果你的服务只被你的本地服务使用,不需要跨进程的工作。你可以实现你的Binder类,使你的客户端可以直接访问你的服务的公有方法。

步骤:

1.      在你的服务中,创建一个Binder的实例,

a.      它包括客户可以访问的公共方法

b.     返回当前服务的实例,他有一些公有方法可供客户端调用

c.      或者,返回一个别的类的实例,这个类持有可供客户调用的一些公共方法的服务。

2.      onBind()方法返回一个Binder的实例。

3.      在客户端,从onServiceConnected()获得一个Binder,并使用服务提供了的方法去调用绑定服务。

倒如,这个服务通过Binder的实现提供了客户端访问服务的一些方法。

 

 

 

LocalBinder为客户端提供了一个getService()方法,可以用来获取当前的LocalService的实例。他允许客户端调用服务的公共方法。例如,客户端可以调用服务的getRandomNumber()方法。

这里有一个Activity绑定到这个服务,并且当点击一次按钮,调用一次getRandomNumber()方法。

 

 

以上实例显示了一个客户端如何使用一个ServiceConnectiononServiceConnected()回调方法绑定到这个服务。

 

使用Messenger(Using a Messenger)

如果你的服务需要远程通信,你可以使用一个Messenger为你的服务提供接口。这个技术允许你不需要AIDL的情况下执行进程间通信(IPC)。

下面是使用Messenger的总结:

·        服务实现一个Handler,为每一个来自客户端的调用接收一个回调。

·        Handler用来创建Messenger实体(他是一个到Handler的引用)

·        Messenger创建一个IBinder,用来作为服务的onBind()的返回值。

·        客户端使用IBinder来初始化一个Messenger(他是到服务的Handler的一个引用),客户端用他来发送Message到服务。

·        服务在他 Handler中接收每一个Message,特别的,在handleMessage()方法中。

用这种方法,服务没有为客户端提供调用的方法。相反,客户端传递message,服务在Handler中接收他。

下面是一个使用Messengar的例子:

 

注意HandlerhandleMessage()方法,他是服务接收消息的地方,并且决定去做什么,基于what成员。

客户端需要做的所有工作是创建一个基于从服务返回的IBinderMessenger,然后使用send()发送一个消息(message)。下面示例一个activity绑定到这个服务,并且向服务传递MSG_SAY_HELLO消息。

 

 

注意,这个示例没有显示服务怎样才能响应到客户端。如果你想要你的服务响应,你也需要在你的客户端中创建 一个Messenger。然后当客户端接到onServiceConnected()回调,他发送一个Message到服务,他在replyTo参数的send()方法中包括客户端的Messenger

 

绑定到一个服务(Binding to a Service)

应用组件可以通过bindService()绑定到一个服务。Android系统然后调用系统的onBind()方法,他返回一个IBinder以供与服务交互。

绑定是异步的。bindService()会立即返回,并不返回IBinder到客户端。为了接收IBinder,客户端必须创建一个ServiceConnection的实例,并将他传递给bindService()方法。ServiceConnection包括一个回调方法,系统可以用来交付IBinder

注:只有ActivityService,和ContentProvider可以绑定到服务,你不能从广播接收者(Broadcastreceiver)来绑定服务。

所以,从客户端绑定一个服务,你需要:

1.      实现一个ServiceConnection

你的实现必须重载以下两个方法:

onServiceConnected()

        系统调用这个方法传递onBind()返回的IBinder

onServiceDisconnected()
        当与服务的连接被异常中断时Android系统会调用这个方法,例如当服务崩溃(crash)了或者被杀死(kill)了。当客户端调用unBind()时系统是不会调用该方法( onServiceDisconnected() )。

2.      调用BindService(),传递ServiceConnection的实现。

3.      当系统调用你的onServiceConnected()方法时,你可以使用接口定义了的方法向服务做出一个调用。

4.      断开与一个服务的连接,使用unBindService()

当你的客户端被销毁了,他将与服务解除绑定关系。但你总是应该在完成与服务的交互之后来解除这种绑定,或者当你的Activity处于Pause状态时,当服务不在使用时应该关闭。

 

例如,以下代码片断连接一个客户端到一个扩展Binder类,所以需要做的是获取一个IBinderLoacalService类并且请求LocalService的实例。

 

 

使用这个ServiceConnection,客户端可以传递他给bindService()来绑定服务。例如:

 

 

bindService()的第一个参数是一个intent,他显式地指明了要绑定的服务(尽管他可以是隐式的)。

第二个参数是这个ServiceConnection对象。

第三个参数是一个标志,他指明的绑定的选项。他通常应该是BIND_AUTO_CREATE,如果这个服务不是活动的将会创建他。别的可能的值有BIND_DEBUG_UNBINDBIND_NOT_FORGOUND,或者是0表示什么也没有。

 

其它注意事项(Additional notes)

这里有关于绑定到服务的一些比较重要的提示:

你总是应该要注意捕捉DeadObjectException异常,当连接被中断了会抛出这个异常。这是远程方法中唯一抛出的异常。

对象是跨进程计数器。

你应该让你的绑定和解除绑定在你的客户端的生命周期的启动与销毁间配对。例如:

如果你仅需要在你的Activity可见期间与服务通信,你应该在onStart()中绑定他,在onStop()中解除绑定。

如果你的Activity在停止之后还接收服务的响应,那你应该在onCreate()中绑定他,在onDestroy()中解除这种绑定。

注:通常你不应该在onResume()中绑定和在onPause()中解除绑定。因为这两个回调在每一个生命周期的转换中都会发生,你应该保持这种处理的最小化。

管理一个绑定服务的生命周期(Managing the Lifecycle of a Bound Service)

当一个服务与所有的客户解除绑定了,Android系统将销毁他(他也被onStartCommand()启动除外)。因此,如果你的服务是一个纯bind的服务,你不需要管理你的服务的生命周期。Android系统将基于他是否绑定到客户端而为你管理他。

然而,如果你的选择了实现onStartCommand()的回调,你必须显示的停止掉你的服务,因为现在系统认为你的服务是started的。这种情况下,服务运行到自己调用stopSelf()或者其它组件调用stopService(),不论他是否绑定到客户端。

如果你的服务既是started,也接受绑定,当系统调用你的onUnbind()方法,如果你更希望下次客户端绑定到服务时接到onRebind()的调用,你可以选择性的返回trueonRebind()返回一个void,但是客户端仍然可以在onServiceConnected()中接到IBinder对象。

原创粉丝点击