标签:
绑定式Service在CS结构中扮演着Server的角色。绑定式Service允许其他组件(如Activity)绑定该Service、发送请求、接收响应、甚至IPC通信( interprocess communication)。绑定式Service通常服务于其他应用程序的组件、且没有明确的后台的概念(does not run in the background indefinitely)。
本文将介绍bound Service的相关内容,包括其创建、与其他应用组件如何绑定 等。有关Service的基础内容,您可以参考我翻译的官方文档:《Android官方文档之Services》;如需访问bound Service的官方原文,您可以点击这个链接:《Bound Services》。
绑定式Service是一个继承于Service的类。它可以与其他应用交互。为了实现绑定Service,您必须重写onBind()方法。该方法返回一个IBinder接口,此接口是绑定式Service与其它应用组件交互的桥梁。
其它应用组件可调用bindService()方法绑定Service。该方法需要传入的参数中包含一个实现了ServiceConnection接口的对象。该对象监控着组件与Service的绑定状态(which monitors the connection with the service)。bindService()方法并不返回数据,而一旦系统创建了组件与Service的连接,ServiceConnection接口中的方法onServiceConnected()将被回调,此时实现了IBinder接口的对象将传递至组件中,这样便实现了Service与绑定组件的通信(to deliver the IBinder that the client can use to communicate with the service)。
Service可同时与多个组件绑定。然而Service仅在绑定的第一个组件时回调onBind()方法以获得IBinder接口对象,之后与该Service绑定的组件都传递的是同一个IBinder接口对象,而且并不再回调onBind()方法。
当Service与绑定它的最后一个组件解绑时,系统将该Service 销毁(destroy),当然若Service还使用start方式启动过(调用startService()方法启动),则该Service并不会destroy。
创建bound Service时,最重要的就是实现onBind()回调方法中的返回接口IBinder,下面将介绍几种不同实现IBinder接口的方式。
以下列举了三种实现IBinder接口的方式:
继承Binder类(Extending the Binder class):Binder是一个实现了IBinder接口的类。若Service只允许被本应用所在的进程访问(这是大多数情况),您需要继承Binder类,并将该对象作为onBind()方法的返回值。这样,与Service绑定的组件就可以通过该返回对象访问Binder的继承类中的public方法、甚至是Service中的方法(to directly access public methods available in either the Binder implementation or even the Service)。
若在您的应用程序中,Service仅作为一个在后台工作的组件,那么这种方式最好不过了。除非您需要Service进行跨进程通信。
IBinder进行跨进程通信,您应当为Service创建一个Messenger对象。这样,Service可以定义一个Handler对象以接受不同类型的Message。Handler是Messenger的基础,它可以在客户端与IBinder共享(This Handler is the basis for a Messenger that can then share an IBinder with the client),并允许使用Message对象向Service端发送指令(allowing the client to send commands to the service using Message objects)。除此之外,亦可以在client端定义Messenger,这样Service端可以回传信息。若您的Service仅是应用程序内部使用,并不需要跨进程通信,那么可以继承Binder类。这样,与Service绑定的组件可以直接访问Service中的public方法。
!请注意:这种继承Binder类的方式仅适用于Service与绑定的组件处于同一应用程序或进程的情况,当然这也是最普遍的情况。举例来说,在播放音乐应用程序中,可以使用这种方式将一个Activity与Service绑定,而Service用于在后台播放音乐。
创建方式:
Binder的内部类。在Service类中定义public方法,以便client端可以访问。在继承于Binder的内部类中返回该Service实例。将该内部类实例作为onBind()返回参数。onServiceConnected()回调方法中接受Binder对象,并访问Service中的public方法。示例如下:
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don‘t need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
在上例中,LocalBinder提供了getService()方法以获得LocalService实例。这样,client端可以通过该实例访问Service中pubic方法。比如,client端可以访问LocalService中的public方法getRandomNumber(),如下所示:
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We‘ve bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
首先,在Activity的onStart()回调方法中调用bindService()绑定LocalService,这时,LocalService中的onCreate()与onBind()依次回调;接着,ServiceConnection 中的onServiceConnected()方法回调,表示组件与Service已绑定,这时可以通过回传给onServiceConnected()中的IBinder接口对象获得LocalService实例,一旦获得了该实例,便可以调用LocalService中的public方法,如getRandomNumber()方法。
!请注意:Service应在合适的时候与组件解除绑定,本例中应在onStop()中解除与Service的绑定。
当Service需要进行IPC通信时,应在Service中使用Messenger。使用Messenger的方式如下:
继承Handler类,并实现回调方法handleMessage(),每当client端访问Service中的方法时,handleMessage()都将回调(receives a callback for each call from a client)。
需在Service中创建一个Messenger对象,构造该对象需传入一个Handler参数。
调用Messenger的getBinder()返回一个IBinder对象,将该对象作为onBind()回调方法的返回值。
client端通过onServiceConnected()回传的IBinder参数,构造Messenger对象,并将Message信息传入Messenger对象,发送给Service。
Service在Handler的handleMessage()方法中接收Message信息。
按照如此方式,client端并没有显式调用Service中的方法,而是传递了Message对象,并在Service的Handler中接收。
以下是Service端示例:
public class MessengerService extends Service {
/** Command to the service to display a message */
static final int MSG_SAY_HELLO = 1;
/**
* Handler of incoming messages from clients.
*/
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
以下是client端接收示例:
public class ActivityMessenger extends Activity {
/** Messenger for communicating with the service. */
Messenger mService = null;
/** Flag indicating whether we have called bind on the service. */
boolean mBound;
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the object we can use to
// interact with the service. We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mBound = false;
}
};
public void sayHello(View v) {
if (!mBound) return;
// Create and send a message to the service, using a supported ‘what‘ value
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, MessengerService.class), mConnection,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}
本例中并未包含Service端向client端发送消息的逻辑,如需要Service答复client发送的消息,需在client端也创建一个Messenger对象,当onServiceConnected()方法被回调时,在send()方法中传入replyTo参数。
绑定Service是一个异步过程(The binding is asynchronous):应用程序中的组件调用bindService()绑定一个Service,bindService()立即返回;接着系统回调Service的onBind()方法,而client并不会接收到IBinder参数,为了接收该参数,需要创建一个ServiceConnection实例,并将该实例传入bindService()中,系统会将IBinder回传至ServiceConnection的回调方法中(The ServiceConnection includes a callback method that the system calls to deliver the IBinder)。
!请注意:只有activities、services、content providers可以绑定Service, broadcast receiver不能绑定Service(you cannot bind to a service from a broadcast receiver)。
所以,绑定Service应按如下步骤:
实现ServiceConnection接口;
实现onServiceConnected()方法:当client与Service建立绑定时,系统回调该方法,并将onBind()返回的IBinder参数回传至该方法中;
实现onServiceDisconnected()方法:当绑定的Service意外终止时( unexpectedly lost),系统回调该方法,如Service被进程kill或Service崩溃(crashed)。系统若回调unBindService()方法,将不会回调onServiceDisconnected()方法。
bindService(),并传入ServiceConnection的实现类对象;onServiceConnected()时,表示client与Service已绑定,此时可以访问Service中的public方法。系统回调unbindService(),解除绑定。
下面的代码片段演示了如何绑定Service:
LocalService mService;
private ServiceConnection mConnection = new ServiceConnection() {
// Called when the connection with the service is established
public void onServiceConnected(ComponentName className, IBinder service) {
// Because we have bound to an explicit
// service that is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
// Called when the connection with the service disconnects unexpectedly
public void onServiceDisconnected(ComponentName className) {
Log.e(TAG, "onServiceDisconnected");
mBound = false;
}
};
下面演示了启动绑定的方式:
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
其中第三个参数表示绑定的模式,通常为BIND_AUTO_CREATE,表示当Service还尚未处于alive状态时创建该Service。其它可用的参数为BIND_DEBUG_UNBIND、BIND_NOT_FOREGROUND,若不打算指定模式,可传入0。
当连接错误时,系统会抛出DeadObjectException异常,这也是在client端调用Service中的方法时可能抛出的唯一异常(This is the only exception thrown by remote methods)。
binding 和 unbinding应成对出调用。
若当Activity在前台处于运行状态时,需要与绑定的Service交互,那么应在onStart()方法中bindService(),在onStop()中unbindService()。
若当Activity在后台处于stop状态时,那么应在onCreate()方法中bindService(),在onDestroy()中unbindService()。此时系统将更易kill该Service。
!请注意:请不要在onResume() 和 onPause()方法中绑定、解绑Service,因为这两个生命周期回调方法经常被回调,频繁的绑定与解绑会降低程序的执行效率。
当Service不再与任何Client绑定时,系统将回收该Service(除非Service也用Start方式启动了(将回调onStartCommand()方法)),您无需手动管理一个纯bound Service的生命周期(you don’t have to manage the lifecycle of your service if it’s purely a bound service),系统会自动管理。
无论Service绑定了多少个client,若您还回调了onStartCommand()方法,那么必须显式stop该Service,可以通过在Service中调用stopSelf()方法、或在其他组件中调用stopService()stop该Service。
若通过两种方式(start、bound)同时启动了一个Service,那么如果希望Service在下一次绑定该client时回调onRebind()方法,应在onUnbind()方法中返回true。按照这种方式,再次与该Service绑定的client仍可以在onServiceConnected()方法中接收到回传的IBinder 参数。如下图所示:
标签:
原文地址:http://blog.csdn.net/vanpersie_9987/article/details/51398817