To provide binding for service, you must implement the onBind()
method. This method returns anIBinder
object that defines the interface that clients can use to interact with the service.
三种不同的方式,说白了就是通过onBind()返回三种不同类型的IBinder
object。
一、可以返回自定义的Binder(继承自Binder),并且在其中提供public methods that the client can call。
通常情况下,we returns the current Service
instance, or an instance of another class hosted by the service with public methods theclient can call.
private final IBinder mBinder = new LocalBinder(); public class LocalBinder extends Binder { LocalService getService() { // Return this instance of LocalService so clients can call public methods return LocalService.this; } }
优点:
1. 使用简单,client在onServiceConnected()拿到Binder之后,可以直接cast到原本的类型,进行使用。
缺点:
1. 必须在同一个进程中使用,因为一般自定义的Binder不会按照IPC的要求实现Binder中的接口,如何支持IPC,请参看AIDL实现的Binder类。
注意:
1. 此种方法调用service的function时,就跟一个普通的函数调用一样,在当前线程执行,而不像IPC那样,service端的function都是在binder thread中执行。
三、使用AIDL,onBind()返回ServiceInterface.Stub mBinder = new ServiceInterface.Stub(){ }。
编译工具会根据.aidl文件生成一个.java文件,里面有AIDL实现的Binder类。例如,我们提供的.aild文件如下:
package com.baidu.test.aidl; import com.baidu.test.aidl.ClientInterface; interface ServiceInterface { void register(ClientInterface client); void serviceFun(); void invokeClientCallBack(); }
package com.baidu.test.aidl; public interface ServiceInterface extends android.os.IInterface { public void register(com.baidu.test.aidl.ClientInterface client) throws android.os.RemoteException; public void serviceFun() throws android.os.RemoteException; public void invokeClientCallBack() throws android.os.RemoteException; // ======================== Stub用在service端 ================================ public static abstract class Stub extends android.os.Binder implements com.baidu.test.aidl.ServiceInterface { private static final java.lang.String DESCRIPTOR = "com.baidu.test.aidl.ServiceInterface"; static final int TRANSACTION_register = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_serviceFun = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_invokeClientCallBack = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); public Stub() { // from Binder, Convenience method for associating a specific interface with the Binder. // After calling, queryLocalInterface() will return the given owner IInterface // when the corresponding descriptor is requested. this.attachInterface(this, DESCRIPTOR);// public void attachInterface (IInterface owner, String descriptor) } public static com.baidu.test.aidl.ServiceInterface asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } //由于attachInterface()是在service调用的,所以client调用queryLocalInterface()会返回null,从而在client端使用的是Proxy。 android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.baidu.test.aidl.ServiceInterface))) { return ((com.baidu.test.aidl.ServiceInterface)iin); } return new com.baidu.test.aidl.ServiceInterface.Stub.Proxy(obj); } @Override // from IInterface public android.os.IBinder asBinder() { return this; } @Override // from Binder // service端的Stub实现了onTransact(),service在其中处理client发出的调用, // 而client端用的Proxy就没有实现onTransact(),而只是调用了transact()。 public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_register: { data.enforceInterface(DESCRIPTOR); com.baidu.test.aidl.ClientInterface _arg0; _arg0 = com.baidu.test.aidl.ClientInterface.Stub.asInterface(data.readStrongBinder()); this.register(_arg0); reply.writeNoException(); return true; } case TRANSACTION_serviceFun: { data.enforceInterface(DESCRIPTOR); this.serviceFun(); reply.writeNoException(); return true; } case TRANSACTION_invokeClientCallBack: { data.enforceInterface(DESCRIPTOR); this.invokeClientCallBack(); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } // ======================== Proxy用在client端 ================================ private static class Proxy implements com.baidu.test.aidl.ServiceInterface { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override // from IInterface public android.os.IBinder asBinder() { return mRemote; } @Override // from IBinder, Get the canonical name of the interface supported by this binder. public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } public void register(com.baidu.test.aidl.ClientInterface client) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeStrongBinder((((client!=null))?(client.asBinder()):(null))); mRemote.transact(Stub.TRANSACTION_register, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } public void serviceFun() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_serviceFun, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } public void invokeClientCallBack() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_invokeClientCallBack, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } // ======================== Proxy用在client端 end ================================ } // ======================== Stub用在service端 end ================================ }service端相关代码如下:private final ServiceInterface.Stub mBinder = new ServiceInterface.Stub() { @Override public void register(ClientInterface client) throws RemoteException { } @Override public void serviceFun() throws RemoteException { } @Override public void invokeClientCallBack() throws RemoteException { } }; @Override public IBinder onBind(Intent t) { return mBinder; }client端的相关代码如下:private ServiceInterface mService; private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { mService = ServiceInterface.Stub.asInterface(service); try { mService.register(mClient); } catch (RemoteException e) { e.printStackTrace(); } } public void onServiceDisconnected(ComponentName className) { mService = null; } };优点:1. 可以进行IPC。
缺点:
1. 使用复杂,需要编写.aidl文件,而且client端和service端都需要copy一份.aidl文件,以便编译生成对应的.java文件。
2. 由于service端的函数是在binder thread中执行,而系统又帮我们维护了一个binder thread的线程池,所以我们需要在service的函数中考虑线程安全。
注意:
1. 如果client和service在同一个进程,那么即使我们采用了AIDL,由系统生成的代码可以看到通过ServiceInterface.Stub.asInterface(service)取得的实例实际上是本地的instance,所以ADIL调用就会变得和一个普通函数调用一样了,也就意味了service端的函数不会在binder thread中执行,而是在当前线程执行了。
2. Objects are reference counted across processes.也就是说可能出现内存泄露。
二、使用Messager,onBind()返回Messager.getBinder()。
Messager可以使用两中不同的方法创建:
public Messenger (Handler target) public Messenger (IBinder target)1. 通过传入一个handler创建,service端使用;
2. 通过传入一个binder创建,client端使用。
其实Messager的底层实现还是AIDL,只不过帮我们做了封装,使用更方便。
service端的相关代码如下:
private ArrayList<Messenger> mClients = new ArrayList<Messenger>(); private Messenger mMessenger = new Messenger(new IncomingHandler()); @Override public IBinder onBind(Intent t) { return mMessenger.getBinder(); } class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { Log("===> handleMessage()"); LogThreadInfo(); switch (msg.what) { case MSG_REGISTER_CLIENT: mClients.add(msg.replyTo); break; case MSG_UNREGISTER_CLIENT: mClients.remove(msg.replyTo); break; case MSG_SERVICE_FUN_ALPHA: for (int i=mClients.size()-1; i>=0; i--) { try { mClients.get(i).send(Message.obtain(null,MSG_SERVICE_FUN_ALPHA)); } catch (RemoteException e) { // The client is dead. Remove it from the list; mClients.remove(i); } } break; default: super.handleMessage(msg); } } }client端的相关代码如下:
private Messenger mService = null; final Messenger mMessenger = new Messenger(new IncomingHandler()); class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SERVICE_FUN_ALPHA: break; default: super.handleMessage(msg); } } } private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { mService = new Messenger(service); try { Message msg = Message.obtain(null,MSG_REGISTER_CLIENT); msg.replyTo = mMessenger; // 可选项,主要是用来向service注册client,从而实现双向IPC。 mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } public void onServiceDisconnected(ComponentName className) { mService = null; } };优点:
1. 比较方便,而且可以实现进程间通信。
缺点:
1. 必须想办法将Message Id,在service和client之间共享。
注意:
1. 由于service是在main thread中创建,所以我们的Messager(包括构造Messager所需要提供的Handler)都是在main thread中创建的,所以一般情况下,service端的handleMessage()是在main thread中执行的。当然由于Handler创建时可以自定义所用的Looper,所以我们可以在service的onCreate()里面创建自己的线程,并prepare()线程自己的Looper,然后就可以让service端的handleMessage()运行在我们自己的线程中了。