bind service可以實現應用組件綁定本地的service,也可以綁定其他應用的service,在android中每個應用運行在
自己的虛擬機器中,每個虛擬機器對應linux核心中一個進程,所以綁定其他應用的service,可以實現處理序間通訊。
binder是能進行遠程操作的對象的一個基類,一個輕量級的遠端程序呼叫機制,核心部分在IBinder類中定義。
這個類是一個IBinder類的實現,為建立一個本地實現對象提供了標準的支援,後面的綁定都是基於binder來實現。
綁定本地的service並與之互動相對比較簡單,在service中建立一個binder執行個體,此執行個體中需要有一個public方法可供綁定者
調用,在此public 方法中返回service執行個體,這樣就可以調用service中的public方法了。binder執行個體通過onBind回調
方法返回給綁定者:
public class LocalService extends Service { private final IBinder mBinder = new LocalBinder(); private final int mserviceparam=10; 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 getServiceParem(){ return mserviceparam; }}
綁定service通過以下方法實現:
bindService (Intent service, ServiceConnection conn, int flags)
ServiceConnection類中有兩個回調方法,當service綁定成功後和取消綁定會調用這兩個方法:
private ServiceConnection mConnection=new ServiceConnection (){@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// TODO Auto-generated method stub}@Overridepublic void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stub}};
綁定不同應用的service並與之互動,需要藉助其他的類來實現,有兩種方式:messenger 、aidl
1.messenger 中文翻譯“信使”,負責資訊的發送,可以跨進程,
messenger有兩個建構函式:
a . public Messenger (Handler target)
handler是用來處理Messenger發送過來的message,
即一個Messenger會有一個Handler與之相對應,
通過Messenger.getBinder()獲得一個binder對象,在service的onBind()方法中返回給客服端
public class MyService extends Service{ static final int MSG_SEND_FROM_REMOTE=1; static final int MSG_SEND_FROM_LOCAL=2; static final int MSG_RELY_FROM_SERVICE=3; class IncomingHandler extends Handler{ public void handleMessage(Message msg){ switch(msg.what){ case MSG_SEND_FROM_REMOTE: Toast.makeText(getApplicationContext(),"hello,i am from remote,send content is"+msg.getData().getString("sendContent"), Toast.LENGTH_LONG).show(); try {msg.replyTo.send(Message.obtain(null, MSG_RELY_FROM_SERVICE, null));} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();} break; case MSG_SEND_FROM_LOCAL: Log.d("remoteservice", "MSG_SEND_FROM_LOCAL"); Toast.makeText(getApplicationContext(),"hello,i am from local", Toast.LENGTH_LONG).show(); break; default: super.handleMessage(msg); } } } final Messenger mMessenger=new Messenger(new IncomingHandler());@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn mMessenger.getBinder();}}
b. public Messenger (IBinder target)
此建構函式一般用於綁定Service的組件中, 傳入的binder對象是從service返回的,這樣此Messenger就會與service中的
messenger相對應,用此Messenger發送訊息,在service中可以接受到,並做相應處理。
到此我們只實現了從綁定組件發送訊息到service,service不能發送訊息給綁定組件,
如要實現雙向通訊,則需要在綁定組件中再建立一個Messenger對象,用public Messenger (Handler target)構造方法,
把此Messenger賦值給msg.replyTo,一併發送到service中,service用此Messenger發送訊息給綁定組件
private ServiceConnection mConnection=new ServiceConnection (){@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// TODO Auto-generated method stubmMessenger=new Messenger(service);//用service中返回的binder構建執行個體send.setEnabled(true);}@Overridepublic void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stubmMessenger=null;send.setEnabled(false);}};
class incomingHandler extends Handler{ //構建綁定組件的handler,service發送過來的message在此處理public void handleMessage(Message msg){switch(msg.what){case MSG_RELY_FROM_SERVICE:sendcontent.setText("service received");break;default:super.handleMessage(msg);}}}
private Messenger reMessenger=new Messenger(new incomingHandler());//構建綁定組件的Messenger
private void sendMessage() throws RemoteException{//發送訊息Message msg=Message.obtain(null, MSG_SEND_FROM_REMOTE, null);Bundle data=new Bundle();data.putString("sendContent",sendcontent.getText().toString());msg.setData(data);msg.replyTo=reMessenger;mMessenger.send(msg);Log.d("remoteservice", "sendMessage");}
2.AIDL android interface definition language 介面定義語言,
在src/ 目錄中建立一個以.aidl為尾碼名的介面定義檔案,android SDK工具會自動在 gen/ 目錄中建立名字一樣的java檔案,
java檔案是一個Ibinder介面檔案。
如定義的.aidl檔案為:
package txj.remoteservice;interface IRemoteService { void showResult();}
會自動產生一個.java 檔案:
/* * This file is auto-generated. DO NOT MODIFY. * Original file: E:\\android\\newworkspase\\RemoteService\\src\\txj\\remoteservice\\IRemoteService.aidl */package txj.remoteservice;public interface IRemoteService extends android.os.IInterface{/** Local-side IPC implementation stub class. */public static abstract class Stub extends android.os.Binder implements txj.remoteservice.IRemoteService{private static final java.lang.String DESCRIPTOR = "txj.remoteservice.IRemoteService";/** Construct the stub at attach it to the interface. */public Stub(){this.attachInterface(this, DESCRIPTOR);}/** * Cast an IBinder object into an txj.remoteservice.IRemoteService interface, * generating a proxy if needed. */public static txj.remoteservice.IRemoteService asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof txj.remoteservice.IRemoteService))) {return ((txj.remoteservice.IRemoteService)iin);}return new txj.remoteservice.IRemoteService.Stub.Proxy(obj);}@Override public android.os.IBinder asBinder(){return this;}@Override 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_showResult:{data.enforceInterface(DESCRIPTOR);this.showResult();reply.writeNoException();return true;}}return super.onTransact(code, data, reply, flags);}private static class Proxy implements txj.remoteservice.IRemoteService{private android.os.IBinder mRemote;Proxy(android.os.IBinder remote){mRemote = remote;}@Override public android.os.IBinder asBinder(){return mRemote;}public java.lang.String getInterfaceDescriptor(){return DESCRIPTOR;}@Override public void showResult() 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_showResult, _data, _reply, 0);_reply.readException();}finally {_reply.recycle();_data.recycle();}}}static final int TRANSACTION_showResult = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);}public void showResult() throws android.os.RemoteException;}
其中的stub抽象內部類繼承了binder和實現了自己定義的介面
在service中需建立一個類extends Stub 並實現自己定義的介面方法,在onbind()方法中返回一個此類的對象。
public class AidlService extends Service { private IRemoteService.Stub mbindder=new IRemoteService.Stub() {@Overridepublic void showResult(){// TODO Auto-generated method stub//Toast.makeText(AidlService.this, "the toast show from AidlService", Toast.LENGTH_LONG).show();Log.d("remoteservice","showResult");}};@Overridepublic IBinder onBind(Intent intent) {// TODO: Return the communication channel to the service.return mbindder;} public void onDestroy(){ Log.d("remoteservice","onDestroy"); super.onDestroy(); }}
把此.aidl檔案複製到需要綁定此服務的應用的src/ 檔案目錄中(包名也要一樣),也會在gen/中自動產生相對應的java檔案。
綁定組件在綁定成功後會得到service返回的binder,通過下面方法得到自己定義介面類型的對象,即可調用service中實現的方法:
mAidlService=IRemoteService.Stub.asInterface(service);
實現代碼:
private ServiceConnection mAidlConnection=new ServiceConnection(){@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// TODO Auto-generated method stubmAidlService=IRemoteService.Stub.asInterface(service);Log.d("ConMainActivity", "onServiceConnected");try {mAidlService.showResult();} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stub}};
源碼:稍後奉上