Android 数据绑定,android服务是什么
绑定服务是一种具有接口的服务,用于促进客户端和服务器之间的通信。服务允许组件(如活动)绑定它。组件可以发送请求、接收响应,并在进程间与服务进行通信。绑定服务通常的生命周期存在于它所服务的其他应用程序组件中,它不会总是在后台运行。
本文告诉您如何创建绑定服务,包括如何绑定服务。
基础知识
服务允许其他组件绑定它并与之交互。为了使服务具有绑定功能,有必要实现onBind()方法,该方法返回IBinder对象,该对象定义了客户端如何与服务器通信。
绑定到已启动的服务
正如在服务文档中所讨论的,您可以创建一个既已启动又已绑定的服务。也就是说,可以通过调用startService()来启动服务,这允许服务无限期运行,也允许客户端通过调用bindService()来绑定到服务。
如果您确实允许您的服务被启动和绑定,那么当服务被启动时,当所有客户端解除绑定时,系统不会销毁该服务。相反,您必须通过调用topSelf()或topService()来显式停止该服务。
尽管您通常应该实现orenbind()或StartCommand(),但有时也有必要两者都实现。例如,音乐播放器可能会发现允许其服务无限期运行并提供绑定很有用。这样,活动可以启动服务来播放一些音乐,即使用户离开应用程序,音乐也会继续播放。然后,当用户返回到应用程序时,活动可以绑定到服务以重新获得对回放的控制。
在向已启动的服务添加绑定时,请务必阅读关于管理绑定服务的生命周期一节,以获得关于服务生命周期的更多信息。
客户端可以调用bindService()方法来绑定到服务。当它被绑定后,它必须提供serviceConnection的实现,该实现可以监控与服务的连接。bind()方法会立即返回,没有值。但是,当系统在客户端和服务器之间创建链接时,会调用ServiceConnection上的onServiceConnected(),并获取IBinder对象。
一个服务可以同时连接到每个客户端。但是,当系统第一次调用onBind()时,只会返回IBinder对象。系统会将这个IBinder对象返回给绑定它的客户端,不会重复调用onBind()。
没有客户绑定的时候,系统会销毁服务。
在实现绑定服务时,定义IBinder接口非常重要。有许多方法可以定义这个接口,下面将会讨论。
创建绑定服务
要创建绑定服务,必须提供IBinder接口。有三种方法可以定义该接口:
扩展Binder类如果这个服务只为当前的应用服务,并且运行在同一个进程中,那么创建的接口必须继承Binder类,并在onBind()方法中返回。客户可以通过它获得Binder对象,通过它可以直接访问常用功能。
当服务只服务于自己的应用程序时,这是首选技术。
使用Messenger如果需要在不同进程之间使用接口,可以使用Messenger为服务类创建接口。通过这种方式,服务定义了用于处理不同消息对象的处理程序。这个处理程序是Messenger的基础,它可以与客户共享IBinder,并允许客户用消息向服务发送命令。点,客户端可以自定义Messenger,这样服务就可以发回消息。
这是进程间最简单的通信方式。因为Messenger队列中的所有请求都发生在一个线程上,所以不需要考虑服务的线程安全性。
使用Aidlaidl (Android接口定义语言)可以将对象分解成系统可以识别的单元,已经达到了进程间通信的能力。在以前的技术中,所使用的信使实际上是基于AIDL的结构。如上所述,Messenger在一个线程中创建了所有客户请求的队列。如果希望服务同时处理多个请求,可以直接使用AIDL。在这种情况下,服务必须能够处理多线程,并且是线程安全的。
要直接使用aidl,必须创建一个定义程序的接口文件,后缀为。AIDL。Android SDK工具可以通过这个文件生成实现这个接口并处理IPC的抽象类,自定义服务需要继承这个抽象类。
注意:大多数应用不需要使用AIDL来创建绑定服务,因为它可能需要多线程功能,实现起来更复杂。就AIDL而言,它不适合大多数应用程序,本文将不讨论AIDL的使用。如果你需要直接使用AIDL,你可以查阅AIDL文档。
扩展Binder类
如果服务只在这个应用中使用,不需要进程间通信,从而实现客户端可以直接访问的Binder类,可以帮助客户端访问服务中的常用方法。
注意:这个服务必须在同一个应用程序和进程中才能工作,这种方法也是最常见的。例如,在音乐应用程序中,activity需要与它自己服务绑定,以便在后台播放音乐。
下面是设置它的方法:
在服务中,创建一个Binder实例,它必须满足:
包括客户端可以调用的常用方法。
返回当前服务实例
或者,返回另一个类的实例。
onBind()方法返回一个Binder对象。
在客户端,从onServiceConnected()获取Binder对象,调用提供的方法操作绑定服务。
注意:服务和客户端之所以必须在同一个应用程序中,是因为客户端可以将返回的对象强制转换为合理的对象,以及调用它的API。服务和客户端必须在同一个进程中,这不能处理进程之间的信号处理。
例如,下面是服务,客户端可以通过绑定器调用它的方法:
publicsclasslocalserviceextendsservice {
//给客户端的活页夹
privatefinalIBinder MB inder=new local binder();
//随机数生成器
privatefinaldrandom mGenerator=new random();
/**
*用于客户端绑定器的类。因为我们知道这项服务总是
*与客户端运行在相同的进程中,我们不需要处理IPC。
*/
publicsclasslocalbinderextendsbinder {
LocalService getService(){
//返回LocalService的这个实例,以便客户端可以调用公共方法
returnLocalService.this
}
}
@覆盖
publicIBinder onBind(意图intent){
返回mBinder
}
/**客户端方法*/
publicint getRandomNumber(){
返回m generator . nextint(100);
}}
LocalService可以通过clientlocalbinder (getService())的常用方法获得。客户端可以通过这个服务调用它的公共方法。例如,客户端可以调用getRandomNumber()。
以下活动绑定到LocalService,双击按钮时调用getRandomNumber():
public class binding activity extends activity {
LocalService mService
boolean mBound=false
@覆盖
protected void onCreate(Bundle saved instancestate){
super . oncreate(savedInstanceState);
setContentView(r . layout . main);
}
@覆盖
protectedvoid onStart(){
super . onstart();
//绑定到LocalService
Intent intent=newIntent(this,local service . class);
bindService(intent,mConnection,Context。BIND _ AUTO _ CREATE);
}
@覆盖
protectedvoid onStop(){
super . onstop();
//解除与服务的绑定
if(mBound){
unbindService(MC connection);
mBound=false
}
}
/**单击按钮时调用(布局文件中的按钮附加到
*此方法带有android:onClick属性)*/
publicvoid onButtonClick(视图v){
if(mBound){
//从LocalService调用方法。
//但是,如果这个调用可能会挂起,那么这个请求应该
//发生在单独的线程中,以避免降低活动性能。
int num=m服务。getrandomnumber();
Toast.makeText(this, num: num,Toast .LENGTH_SHORT).show();
}
}
/**定义服务绑定的回调,传递给bindService() */
privateServiceConnection MC connection=newServiceConnection(){
@覆盖
public void onServiceConnected(组件名类名,
对象服务){
//我们已经绑定到本地服务,转换对象并获取本地服务实例
LocalBinder binder=(LocalBinder)服务;
m服务=装订器。获取服务();
mBound=true
}
@覆盖
public void onServiceDisconnected(组件名称参数0){
mBound=false
}
};}
上面的实例展示客户如何实现服务连接和实现服务连接的回调方法onServiceConnected()与服务绑定。
注意:上面的例子并没有显示的取消和服务的绑定,所有的客户必须在合适的时候解除绑定(活动停止)。
想了解更加详细的例子代码,可以在分类里面查找LocalService.java和LocalServiceActivities.java。
使用信使
与接口描述语言相比
当您需要执行工业程序控制( industrial process control的缩写)时,为您的接口使用一个信使比用接口描述语言实现它更简单,因为一个信使会对服务的所有调用进行排队,而纯接口描述语言接口会同时向服务发送请求,然后服务必须处理多线程。
对于大多数应用程序,服务不需要执行多线程,因此使用消息允许服务一次处理一个调用。如果你的服务是多线程的很重要,那么你应该使用aidlt来定义你的接口。
如果服务需要与远程的进程通讯,可以用送信人;通信员为服务提供一个接口。这种技术可以处理进程间的通讯。
下面是使用送信人;通信员的简介:
服务要实现处理者,它可以收到每一个客户调用的回调。
处理者用于创建送信人;通信员对象(这是对处理者的引用)。
送信人;通信员创建一个伊宾德,客户调用onBind()时,IBinder要返回给客户的
客户通过对象实例化信使(引用服务的句柄),信使为了客户发送消息对象到服务。
服务通过处理者收到每一个消息,在handleMessage()方法明确的处理。
利用这种方式,服务中没有方法可一个被客户调用客户。通过传递消息(消息)到服务的处理者中。
下面是一个简单的例子,通过送信人;通信员的方式实现:
publicsclassmessengerserviceextendsservice {
/**命令到服务以显示消息*/
静态final int MSG _ SAY _ HELLO=1;
/**
*客户端传入消息的处理程序。
*/
类别incominghandlerextendshandler {
@覆盖
公共void句柄消息(Message msg){
switch(msg.what){
案例消息_说_你好:
吐司。制作文本(getApplicationContext(), hello!,吐司. LENGTH_SHORT)。show();
打破;
默认值:
超级棒。处理消息(msg);
}
}
}
/**
*我们为客户端发布的目标,用于向IncomingHandler发送消息。
*/
final messenger mMessenger=new messenger(newIncomingHandler());
/**
*当绑定到服务时,我们向送信人;通信员返回一个接口
*用于向服务发送消息。
*/
@覆盖
publicIBinder onBind(意图意图){
吐司。制作文本(getApplicationContext(), binding ,Toast).LENGTH_SHORT).show();
返回马森格先生。get binder();
}}
主意:处理程序的handleMessage()方法收到消息,并且根据消息的什么变量确定需要做什么。
客户的需要实现的是,基于返回的对象创建送信人;通信员对象,并且通过发送()发送消息给服务的处理程序。例如,下面的活动绑定了服务,而且传递MSG _ SAY _消息到服务中处理:
publiclassactivitymessageextendssactive {
/**用于与服务通信的信使.*/
Messenger mService=null
/**指示我们是否对服务调用了约束的标志。*/
布尔姆本德
/**
*用于与服务的主接口交互的类。
*/
privateServiceConnection MC connection=newServiceConnection(){
public void onServiceConnected(组件名类名,IBinder服务){
//当与服务的连接被
//已建立,给了我们可以用来
//与服务交互。我们正在与
//服务,所以这里我们得到了一个客户端
//原始对象对象的表示形式。
mService=newMessenger(服务);
mBound=true
}
public void onServiceDisconnected(组件名类名){
//当与服务的连接被
//意外断开连接——即其进程崩溃。
mService=null
mBound=false
}
};
publicvoid sayHello(视图五){
如果(!mBound)返回;
//使用支持的“什么”值创建消息并将其发送到服务
Message msg=Message.obtain(null,MessengerService .MSG_SAY_HELLO,0,0);
尝试{
mservice。发送(msg);
}catch(远程异常e){
e。printstacktrace();
}
}
@覆盖
受保护的void onCreate(Bundle saved instancestate){
超级棒。oncreate(savedInstanceState);
setContentView(r . layout。main);
}
@覆盖
protectedvoid onStart(){
超级棒。onstart();
//绑定到服务
bindService(newIntent(this,MessengerService.class),mConnection,
语境. BIND _ AUTO _ CREATE);
}
@覆盖
protectedvoid onStop(){
超级棒。onstop();
//解除与服务的绑定
if(mBound){
unbindService(MC连接);
mBound=false
}
}}
注意:这个例子没有体现服务是如何响应客户。如果想服务响应客户,需要在客户里面创建一个信使。当客户收到onServiceConnected()回调,就会发送消息到服务,发送()方法的消息变量回复包括客户端的信使。
可以从MessengerService.java(服务)和messengerserviceactivities。Java(客户端)例子中知道如何提供双向通讯。
绑定到服务
应用的组件调用bindService()可以绑定服务。系统会调用服务的onBind()方法,返回一个伊宾德,以便组件能与服务很好的交互。
绑定过程是异步bindService()能很快的返回,并且不会返回对象到客户端客户。收到对象时,会创建服务连接并且通过它绑定到服务。服务连接包括一个系统调用传递对象的方法。
注意:仅仅活动、服务、和内容提供商能够与服务绑定-不能把广播收音机与服务绑定。
因此,为了让客户与服务绑定,必须:
实现服务连接。
实现必须重写两个方法:
onServiceConnected()系统调用这个函数来传递服务的onBind()方法返回的伊宾德.onservicedisconnected()Android系统在服务的连接意外丢失时调用这个函数,例如当服务崩溃或被终止时。当客户端解除绑定时,不会调用此函数。
调用绑定服务(),传递服务连接的实现。
当系统调用onServiceConnected()方法,就可以调用服务的方法,能调用的方法必须是定义在接口中的。
调用取消绑定服务()取消与服务的连接。
当客户销毁时,就会取消与服务的绑定,但是当做完任务或者活动停止的时候,要取消绑定,以便服务在不需要的时候能够停止
例如,下面的一段代码通过继承粘合剂类,从而客户和服务可以绑定,因此,需要将返回的对象转换成本地服务,并取得本地服务对象:
local service mServiceprivateServiceConnection MC connection=newServiceConnection(){
//建立与服务的连接时调用
public void onServiceConnected(component name class name,IBinder service){
//因为我们已经绑定到一个显式的
//在我们自己的进程中运行的服务,我们可以
//将其IBinder强制转换为具体的类并直接访问它。
LocalBinder binder=(LocalBinder)服务;
m service=binder . get service();
mBound=true
}
//当与服务的连接意外断开时调用
public void onServiceDisconnected(component name class name){
Log.e(标签, onServiceDisconnected );
mBound=false
}};
通过这个ServiceConnection,客户端可以通过bindService()绑定服务。例如:
Intent intent=newIntent(this,local service . class);
bindService(intent,mConnection,Context。BIND _ AUTO _ CREATE);
第一个变量是指定要通过意图绑定的服务。
第二个参数是ServiceConnection对象。
第三个参数是设置绑定的选项。通常是BIND_AUTO_CREATE,在服务没有运行的时候会自动创建。其他值有BIND_DEBUG_UNBIND和BIND_NOT_FOREGROUND,或者是0(没有任何意义)。
补充说明:
以下是绑定服务时需要注意的事项:
总是捕捉DeadObjectException异常,并在连接断开时将其抛出。这是远程方法抛出的唯一异常。
按对象进程的引用计数。
Bind和unbind与start和close方法成对出现。例如:
当活动可见时,要与服务交互,需要在onStart()方法中绑定它,并在onStop()方法中解除绑定。
当活动需要接收回复时,即使它已经在后台停止,它在onCreate()中被绑定,在onDestroy()中被解除绑定。这意味着您的活动需要在整个运行时间内使用该服务(即使它在后台运行)。因此,如果服务在另一个进程中,然后你增加了服务的权重,系统会先杀死它。注意:通常情况下,不能在onResume()和onPause()活动方法中绑定和解除绑定。这个回调函数在每一个生命周期的转变中都会发生,所以应该保证这个转变发生的越少越好。类似地,如果一个应用程序中有多个活动被绑定到同一个服务,并且两个活动中有多余的活动,那么当前一个活动被挂起时,服务将解除绑定,并重新绑定到另一个活动。(活动生命周期的协调在活动文档中)
更多的例子,你可以在ApiDemos的RemoteService.java中看到如何绑定服务。
管理绑定服务的生命周期
当服务没有被任何客户端绑定时,android系统会将其杀死(除非中间有其他组件调用onStartCommand())。根据这个原理,不需要管理绑定服务的生命周期——Android系统会根据绑定原理自动管理服务。
但是,如果选择onStartCommand()方法,则必须显式停止服务,因为服务的当前状态被视为已启动。在这种情况下,无论是否绑定了任何客户端,服务都会一直运行,直到stopSelf()或其他组件调用stopService()方法。这意味着当一个绑定的服务通过onStartCommand()启动时,需要stopSelf()和stopService()方法来停止它,即使中间绑定了其他客户端。
补充了,如果服务已经启动并接受了客户端的绑定,那么当系统调用onUnbind()方法时,如果希望客户端下次绑定服务时调用onBind(),可以选择返回true,(而不是再次调用onBind())。onBind()返回void,但是客户端仍然接受onServiceConnected()中的IBinder。下图说明了上述逻辑。
图一。启动并允许绑定的服务的生命周期。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。