转载请注明出处:http://blog.csdn.net/zhouli_csdn/article/details/45498809
Bound Services
绑定服务允许组件绑定到服务,发送请求,接收结果,甚至进程间通信。绑定服务仅仅存活于服务于其它组件的时候,它不会长期在后台运行。
The basics
为了提供绑定服务,你必须实现onBind方法,这个方法返回一个IBinder,定义了交互的接口。你必须实现ServiceConnection类,监控服服务的连接。bindService方法并不会立刻返回一个值,但是当系统建立了client和service的连接时,它会调用ServiceConnection的onServiceConnected方法,并且传递IBinder。多个clients可以绑定到一个服务,但是只有第一个client调用onBind方法时,才会调用onBind方法,以后就不会调用了。当最后一个client调用unBind方法时,系统会杀死这个服务(除非也调用startService)。
Creating a Bound Service
你必须提供一个IBinder,三种方法:
继承Binder类:
如果你的service对于你的应用是私有的,并且在同一个进程中运行,你可以实现该类,并通过onBind方法返回该类的一个实例。这时,client就可以访问IBinder和Service中的public方法。
如果你的服务被其它应用使用或者运行在单独的进程中,你不能使用这种方法。
Using a Messenger:
如果你需要一个接口工作于不同的进程,你可以为service创建一个Messenger接口。这种方法,service定义了一个Handler处理不同类型的请求。Messenger能够和client分享一个IBinder,允许client使用Message发送请求。通常,client也可以定义一个Messenger,这样service可以将Message送回。
这是最简单的进程间通信,因为Messenger将所有的请求都入列到一个线程中,这意味着一次只能执行一个请求,所以你不必担心线程安全问题。
Using AIDL:
AIDL做了所有的工作使得可以将对象分解成操作系统可以理解的原语,然后在不同进程间执行IPC。Messenger方法底层就是使用了AIDL 的机制实现的。如果你想service能够同时处理多个请求,你可以直接使用AIDL。这种情况下,你必须实现多线程安全问题。
要使用AIDL,你必须创建一个.aidl文件来定义编程接口。你可以使用sdk工具来根据这个文件生成一个抽象类(继承该接口)处理IPC。
接下来你可以在service中继承该抽象类。
注意:大多数应用程序不该使用AIDL来创建一个bind service.因为这会造成多线程安全问题,如果你想实现,你可以参照android的AIDL文档。
继承Binder类:
注意:这仅仅只有client和service在同一个应用并且在同一个进程中才会有效。
1在service中创建一个IBinder对象:
1).包含一些public方法,这样client可以调用
2).返回当前service对象(包含一些public方法,client可以调用),
3).或者返回一个service的内部类包含一些public方法,这样client可以调用
2.在onBind方法中返回IBinder对象实例。
3.在client中,从onServiceConnected方法接收这个Binder。然后调用提供的方法调用服务。
注意:之所以client和service必须在同一个应用中是因为这样才可以使client转换返回的对象和调用它的apis。因为这种方法并不会在进程间通信,所以必须在同一进程运行。
例如:
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方法给client,并返回当前service对象。这样client就可以调用service的public方法。
下面的例子是activity调用service的public方法:
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; } }; }
使用Messenger:
如果你希望你的service可以使用远程进程调用,你可以使用这种方法。它可以是你避免使用AIDL实现进程间通信。
如何使用:
1.service实现一个Handler接口,接收client的请求调用
2.这个Handler用来创建一个Messenger对象,并且包含了此handler的一个引用。
3.这个Messenger对象创建一个IBinder对象,并通过onBind方法返回给client。
4.client用这个IBinder对象实例化这个包含了service的handler的Messenger对象,client使用这个handler发送Message给service。
5.service在它的handleMessage方法中处理message。
这种方法,client不会调用service的方法,而是通过发送给service的message交给handler处理。
下面是一个例子:
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仅仅只需要根据service返回的IBinder对象在ServiceConnection的onServiceConnected方法中创建Messenger对象,并通过send方法发送消息。例子:
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中创建一个Messenger,当client接收到onServiceConnected方法时,通过send方法将messenger发送给service。
注意:仅仅activity,contentprovider,service可以绑定到一个服务,broadcastreceiver不能够绑定到一个服务
。
ServiceConnection:
onServiceConnected:系统调用这个方法传递由onBind方法返回的IBinder
onServiceDisconnected:系统会在和服务的连接意外丢失时调用此方法。例如:当service崩溃或者被杀死。client调用unBind方法时并不会调用此方法。
当client被销毁时,它会解除和service的绑定,但是你应该在和service完成交互时或者你的activity执行pause时解除绑定。这时,服务就可以在不用的时候结束。
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);第三个参数应该为BIND_AUTO_CREATE,这样在service还没有创建时可以创建service。
需要注意的地方:
1.你必须注意DeadObjectException,当连接破坏的时候会被调用。这是唯一的一个被远程方法抛出的异常。
2.objects是被跨进程引用计数。
3.你应该在client的匹配的生命周期进行onBind和unBind。
1)例如你只希望在activity可见时与服务通信,那么你可以在onStart中onBind,在onStop中unBind。
2)如果你想在activity停止时仍然可以收到结果,你可以在onCreate和onDestroy中执行。必须知道的是,这意味着你的activity在整个生命周期中都会使用service。
如果service运行在两外一个进程中,所以你增加了进程的杀死权重,系统很可能会杀死它。
注意:不要再activity的onResume和onPause方法中onBind和unBind。因为如果有多个activities绑定到一个服务。并且其中两个有一个过渡,那么你在过渡过程中首先可能会销毁服务,然后在下一个activity创建服务。
管理绑定服务的生命周期
如果你的服务接受绑定,当系统调用unBind方法时,如果你希望在下一次一个client绑定到service时被系统调用onRebind方法而不是onBind方法时,你可以在unBind方法中返回true。onRebind返回void,但是client仍然可以在onServiceConnected方法中接收到IBinder。下面是这种生命周期: