原文URL:Bound Services
(1)
Bound service在客户/服务器模式中充当服务端。一个Bound Service允许组件(比如Activities)绑定到该Service上,发送请求,接收响应,甚至是进行进程间通信(IPC)。一个Bound Service只存活在当它为其他的应用组件服务的时候,并且不会永远在后台运行下去。
本文档将向你展示如何创建一个Bound Service ,包括如何从其他的应用组件绑到到该Service。但是,你也应该参考一下Services文档中的关于Services的常识信息,例如,如何从一个Service提交Notifications,将Service 设置为前台运行等等。
(2)The Basics
Bound Service 是Service类的子类,它允许其他的应用程序绑定该Service,并和它进行交互。为了使一个Service 具有绑定功能,你必须实现onBind()回调方法。该方法返回一个IBinder对象,该对象定义了clients能用来与该Service 进行交互的编程接口。
client 可以通过调用bindService()方法绑定该Service。当进行绑定时,必须提供一个ServiceConnection的实现,它用来监视与Service 的连接状态。bindService()方法会立即返回,并且没有返回值,但是,当Android 系统创建client与Service 之间的连接时,系统会调用ServiceConnection中的onServiceConnection()方法,把IBinder 对象交给client,这样的话,client可以使用该对象与Service 进行交互。
多个client可以同时连接该Service。但是,系统只会在第一个client绑定的时候调用你Service 的onBind()方法获取IBinder对象。然后系统会把这一个IBinder对象交给后续绑定到该Service的其他的client,而不会再调用onBind()方法。
当最后一个client解除与该Service 的绑定关系后,系统会销毁该Service (除非该Service 也是用startService()方法启动创建的)。
当你实现你的Bound Service 时,最重要的一点就是定义你的onBind()回调方法返回的IBinder 接口。有三种不同的方式可以定义你的Service 的IBinder 接口,下面将一一介绍各种方法。
(3)Creating a Bound Service
当创建一个具有绑定功能的Service 时,你必须提供一个IBinder 接口,它提供了client用来与该Service 交互的编程接口。你可以有三种方式定义此接口:
如果你的Service 只在你自己的应用中使用,并且和client运行在同一个进程中(这是一普遍的情况),你应该通过继承Binder类并从onBind()方法返回它的一个实例的方式创建该接口。client可以接收该Binder对象并使用它直接调用Binder实现类的或者甚至是Service 的public 方法。
如果你的Service 仅仅只是在你的自己应用程度中做一些后台工作,这是一种首选方式。你不能使用此种方式创建IBinder接口的唯一情况就是你的Service 要被其他的应用程序使用,或者跨跃不同的进程。
如果你的Service 只是在自己的应用程序中使用,并且不需要进行跨进程工作,那么你可以通过继承Binder 类来实现你的Binder 类,它可以使client能够直接调用Service 的public 方法。
注意:此种方式只适用于client和service在同一个应用程序和进程中,这是最普遍的情况。例如,XXX
下面是创建过程:
1》在你的Service中,创建一个Binder的实例:
1.1》这个Binder实例含有client要调用的public 方法
1.2》这个Binder实例返回当前的Service实例,该Service 含有client可以调用的public 方法(ps:下面的事例就是采用这种方法)
1.3》或者,XXX
2》从Service的onBind()方法中返回该Binder的实例
3》在client中,从onServiceConnected()回调方法接收此Binder对象实例并调用绑定的Service提供的方法
For example, here's a service that provides clients access to methods in the service through a Binder implementation:
package com.mytest.servicetest; import java.util.Random; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; 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) { // TODO Auto-generated method stub return mBinder; } /** method for clients */ public int getRandomNumber() { return mGenerator.nextInt(100); } }
LocalBinder提供了getService()方法,client通过此方法得到LocalService的实例。client可以通过该实例调用Service 中的public 方法。例如,client可以调用Service 中的getRandomNumber()方法。
下面是一个要绑定LocalService的Activity,并且在该Activity 中,当点击按钮时,调用LocalService 中的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; } }; }
以上事例展示了client如何使用ServiceConnection实例以及onServiceConnected()回调方法绑定Service。下面详细介绍 一下绑定Service的过程。
应用程序组件(Clients)可以调用bindService()方法绑定一个service。然后Android 系统会调用service 的onBind()方法,该方法会返回一个IBinder对象,用来与service 进行交互。
绑定过程是异步的。也就是说,bindService()方法会立即返回并且不会向client返回IBinder对象。为了接收IBinder对象,client必须要创建一个ServiceConnection的实例,并把该实例传递给bindService()方法。ServiceConnection类包含一个回调方法(ps:也就是onServiceConnected()回调方法),Android系统就是用这个回调方法向client返回IBinder 对象的。
注意:只有activities,services和content providers可以绑定service--不可以用broadcast receiver绑定service
从client绑定service时,你必须:
1.实例化ServiceConnection.
实例时必须要重写 两个回调方法:
onServiceConnected()
Android系统会调用此方法将service中的onBind()方法返回的IBinder对象交给client.
onServiceDisconnected()
当client与service的连接忽然断开时,Android系统会调用此方法,比如当service突然崩溃时或者service被kill的时候。
但是,当client与service解除绑定时不会调用此方法。
2.client调用bindService()方法,并将实例化的ServiceConnection对象传递给它。
3.当Android系统调用onServiceConnected()方法时,你可以调用service中定义的接口方法。
4.调用unbindService()方法,解除与service 的绑定关系。
当client销毁时,client将解除与service的绑定关系,但是你应该总是在使用完service之后或者是当Activity暂停时解除绑定,这样的话,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);