您的位置:首页 > 移动开发 > Android开发

Android 复习_Service 二

2011-06-10 20:25 204 查看
BoundServices


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

基础知识
(TheBasics)

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

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

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

当最后一个客户端解除了与服务的绑定,系统将销毁掉这个服务。
(如果该服务也被
startService()启动除外。
)
当你实现你的绑定的服务时,最重要的工作是定义你的
onBind()方法返回的接口。

创建一个绑定服务
(CreatingaBoundService)

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

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

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

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

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

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

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

注:绝大多数应用都不应该使用

AIDL来创建绑定服务,因为他需要多线程能力,且使其实现复习化。

扩展
Binder类
(Extendingthe
Binderclass)

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

步骤:

1.

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

a.

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

b.

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

c.

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

2.


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

3.

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

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

publicclassLocalServiceextendsService{ //Bindergiventoclients privatefinalIBindermBinder=newLocalBinder(); //Randomnumbergenerator privatefinalRandommGenerator=newRandom(); /** *ClassusedfortheclientBinder.Becauseweknowthisservicealways *runsinthesameprocessasitsclients,wedon'tneedtodealwithIPC. */ publicclassLocalBinderextendsBinder{ LocalServicegetService(){ //ReturnthisinstanceofLocalServicesoclientscancallpublicmethods returnLocalService.this; } } @Override publicIBinderonBind(Intentintent){ returnmBinder; } /**methodforclients*/ publicintgetRandomNumber(){ returnmGenerator.nextInt(100); } }

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

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

publicclassBindingActivityextendsActivity{ LocalServicemService; booleanmBound=false; @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protectedvoidonStart(){ super.onStart(); //BindtoLocalService Intentintent=newIntent(this,LocalService.class); bindService(intent,mConnection,Context.BIND_AUTO_CREATE); } @Override protectedvoidonStop(){ super.onStop(); //Unbindfromtheservice if(mBound){ unbindService(mConnection); mBound=false; } } /**Calledwhenabuttonisclicked(thebuttoninthelayoutfileattachesto *thismethodwiththeandroid:onClickattribute)*/ publicvoidonButtonClick(Viewv){ if(mBound){ //CallamethodfromtheLocalService. //However,ifthiscallweresomethingthatmighthang,thenthisrequestshould //occurinaseparatethreadtoavoidslowingdowntheactivityperformance. intnum=mService.getRandomNumber(); Toast.makeText(this,"number:"+num,Toast.LENGTH_SHORT).show(); } } /**Definescallbacksforservicebinding,passedtobindService()*/ privateServiceConnectionmConnection=newServiceConnection(){ @Override publicvoidonServiceConnected(ComponentNameclassName, IBinderservice){ //We'veboundtoLocalService,casttheIBinderandgetLocalServiceinstance LocalBinderbinder=(LocalBinder)service; mService=binder.getService(); mBound=true; } @Override publicvoidonServiceDisconnected(ComponentNamearg0){ mBound=false; } }; }

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

使用
Messenger(UsingaMessenger)

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

下面是使用
Messenger的总结:

·

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

·

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

·

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

·

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

·

服务在他


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

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

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

publicclassMessengerServiceextendsService{ /**Commandtotheservicetodisplayamessage*/ staticfinalintMSG_SAY_HELLO=1; /** *Handlerofincomingmessagesfromclients. */ classIncomingHandlerextendsHandler{ @Override publicvoidhandleMessage(Messagemsg){ switch(msg.what){ caseMSG_SAY_HELLO: Toast.makeText(getApplicationContext(),"hello!",Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } /** *TargetwepublishforclientstosendmessagestoIncomingHandler. */ finalMessengermMessenger=newMessenger(newIncomingHandler()); /** *Whenbindingtotheservice,wereturnaninterfacetoourmessenger *forsendingmessagestotheservice. */ @Override publicIBinderonBind(Intentintent){ Toast.makeText(getApplicationContext(),"binding",Toast.LENGTH_SHORT).show(); returnmMessenger.getBinder(); } }


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

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

publicclassActivityMessengerextendsActivity{
/**Messengerforcommunicatingwiththeservice.*/
MessengermService=null;
/**Flagindicatingwhetherwehavecalledbindontheservice.*/
booleanmBound;
/**
*Classforinteractingwiththemaininterfaceoftheservice.
*/
privateServiceConnectionmConnection=newServiceConnection(){
publicvoidonServiceConnected(ComponentNameclassName,IBinderservice){
//Thisiscalledwhentheconnectionwiththeservicehasbeen
//established,givingustheobjectwecanuseto
//interactwiththeservice.Wearecommunicatingwiththe
//serviceusingaMessenger,soherewegetaclient-side
//representationofthatfromtherawIBinderobject.
mService=newMessenger(service);
mBound=true;
}
publicvoidonServiceDisconnected(ComponentNameclassName){
//Thisiscalledwhentheconnectionwiththeservicehasbeen
//unexpectedlydisconnected--thatis,itsprocesscrashed.
mService=null;
mBound=false;
}
};
publicvoidsayHello(Viewv){
if(!mBound)return;
//Createandsendamessagetotheservice,usingasupported'what'value
Messagemsg=Message.obtain(null,MessengerService.MSG_SAY_HELLO,0,0);
try{
mService.send(msg);
}catch(RemoteExceptione){
e.printStackTrace();
}
}
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protectedvoidonStart(){
super.onStart();
//Bindtotheservice
bindService(newIntent(this,MessengerService.class),mConnection,
Context.BIND_AUTO_CREATE);
}
@Override
protectedvoidonStop(){
super.onStop();
//Unbindfromtheservice
if(mBound){
unbindService(mConnection);
mBound=false;
}
}
}

注意,这个示例没有显示服务怎样才能响应到客户端。如果你想要你的服务响应,你也需要在你的客户端中创建

一个
Messenger。然后当客户端接到
onServiceConnected()回调,他发送一个
Message到服务,他在
replyTo参数的
send()方法中包括客户端的
Messenger。

绑定到一个服务
(BindingtoaService)

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

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

注:只有
Activity

Service
,和
Content
Provider
可以绑定到服务,你不能从广播接收者
(Broadcast
receiver)
来绑定服务。

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

1.

实现一个
ServiceConnection。

你的实现必须重载以下两个方法
:
onServiceConnected()。

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

onServiceDisconnected()。

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

onServiceDisconnected())。

2.

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

3.

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

4.

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

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

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

LocalServicemService;
privateServiceConnectionmConnection=newServiceConnection(){
//Calledwhentheconnectionwiththeserviceisestablished
publicvoidonServiceConnected(ComponentNameclassName,IBinderservice){
//Becausewehaveboundtoanexplicit
//servicethatisrunninginourownprocess,wecan
//castitsIBindertoaconcreteclassanddirectlyaccessit.
LocalBinderbinder=(LocalBinder)service;
mService=binder.getService();
mBound=true;
}
//Calledwhentheconnectionwiththeservicedisconnectsunexpectedly
publicvoidonServiceDisconnected(ComponentNameclassName){
Log.e(TAG,"onServiceDisconnected");
mBound=false;
}
};

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

Intentintent=newIntent(this,LocalService.class);
bindService(intent,mConnection,Context.BIND_AUTO_CREATE);

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

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

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

其它注意事项
(Additionalnotes)

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

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

对象是跨进程计数器。

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

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

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

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

管理一个绑定服务的生命周期
(ManagingtheLifecycleofaBoundService)

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

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

如果你的服务既是
started,也接受绑定,当系统调用你的
onUnbind()方法,如果你更希望下次客户端绑定到服务时接到
onRebind()的调用,你可以选择性的返回
true。
onRebind()返回一个
void,但是客户端仍然可以在
onServiceConnected()中接到
IBinder对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: