Coin163

首页 > android: 使用AIDL实现进程间通信(附示例源码下载)

android: 使用AIDL实现进程间通信(附示例源码下载)

相关标签: android aidl

2021腾讯云限时秒杀,爆款1核2G云服务器298元/3年!(领取2860元代金券),
地址https://cloud.tencent.com/act/cps/redirect?redirect=1062

2021阿里云最低价产品入口+领取代金券(老用户3折起),
入口地址https://www.aliyun.com/minisite/goods

相关推荐:Android 进程间通信(IPC)---AIDL入门

AIDL简介   AIDL是 Android Interface Definition Language的缩写。AIDL 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行 IPC的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序

关于AIDL的介绍及实现步骤等请参考:

http://www.cnblogs.com/hibraincol/archive/2011/09/06/2169325.html

本篇文章只是用一个实例来分析AIDL的实现。

本示例实现的是:AIDL客户端通过AIDL接口获取AIDL服务端中提供的webPage信息,下面详述AIDL通信的实现步骤:

一、编写服务端代码

1. 首先编写AndroidManifest.xml文件:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <? xml  version="1.0" encoding="utf-8"?> < manifest  xmlns:android="http://schemas.android.com/apk/res/android"        package="com.braincol.aidl.service"        android:versionCode="1"        android:versionName="1.0">      < uses-sdk  android:minSdkVersion="8" />        < application  android:icon="@drawable/icon" android:label="@string/app_name">        < service  android:name="RemoteService">          < intent-filter >              < action  android:name="com.braincol.aidl.remote.webpage"/>          </ intent-filter >      </ service >        </ application > </ manifest >

 

可以看到服务端的包名为:com.braincol.aidl.service,且该服务端只需一个service组件提供AIDL服务,service组件的名称为RemoteService,这是待会要实现的Service子类。其中<action android:name="com.braincol.aidl.remote.webpage"/> ,指定了action名称为"com.braincol.aidl.remote.webpage", 客户端会通过该action的名称来找到并连接该服务端。

2. 创建RemoteWebPage.aidl文件

在包com.braincol.aidl.service下创建RemoteWebPage.aidl文件:

1 2 3 4 package  com.braincol.aidl.service;   interface  RemoteWebPage {      String getCurrentPageUrl();     }

可以看到内容很简单,该文件中包含一个RemoteWebPage 接口,并且接口中只有getCurrentPageUrl()这么一个方法,后面的客户端将通过这里提供的getCurrentPageUrl()方法获取想要的信息。

3.生成RemoteWebPage.java文件

保存并编译该工程(在eclipse中编译)会看到 gen/ 目录下的com.braincol.aidl.service包下出现了一个RemoteWebPage.java文件:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 /*   * This file is auto-generated.  DO NOT MODIFY.   * Original file: F:\\workspace\\android\\AIDL-simple\\AIDLService\\src\\com\\braincol\\aidl\\service\\RemoteWebPage.aidl   */ package  com.braincol.aidl.service; public  interface  RemoteWebPage extends  android.os.IInterface {      /** Local-side IPC implementation stub class. */      public  static  abstract  class  Stub extends  android.os.Binder implements  com.braincol.aidl.service.RemoteWebPage      {          private  static  final  java.lang.String DESCRIPTOR = "com.braincol.aidl.service.RemoteWebPage" ;          /** Construct the stub at attach it to the interface. */          public  Stub()          {              this .attachInterface( this , DESCRIPTOR);          }          /**           * Cast an IBinder object into an com.braincol.aidl.service.RemoteWebPage interface,           * generating a proxy if needed.           */          public  static  com.braincol.aidl.service.RemoteWebPage asInterface(android.os.IBinder obj)          {              if  ((obj== null )) {                  return  null ;              }              android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);              if  (((iin!= null )&&(iin instanceof  com.braincol.aidl.service.RemoteWebPage))) {                  return  ((com.braincol.aidl.service.RemoteWebPage)iin);              }              return  new  com.braincol.aidl.service.RemoteWebPage.Stub.Proxy(obj);          }          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_getCurrentPageUrl:              {                  data.enforceInterface(DESCRIPTOR);                  java.lang.String _result = this .getCurrentPageUrl();                  reply.writeNoException();                  reply.writeString(_result);                  return  true ;              }              }              return  super .onTransact(code, data, reply, flags);          }          private  static  class  Proxy implements  com.braincol.aidl.service.RemoteWebPage          {              private  android.os.IBinder mRemote;              Proxy(android.os.IBinder remote)              {                  mRemote = remote;              }              public  android.os.IBinder asBinder()              {                  return  mRemote;              }              public  java.lang.String getInterfaceDescriptor()              {                  return  DESCRIPTOR;              }              public  java.lang.String getCurrentPageUrl() throws  android.os.RemoteException              {                  android.os.Parcel _data = android.os.Parcel.obtain();                  android.os.Parcel _reply = android.os.Parcel.obtain();                  java.lang.String _result;                  try  {                      _data.writeInterfaceToken(DESCRIPTOR);                      mRemote.transact(Stub.TRANSACTION_getCurrentPageUrl, _data, _reply, 0 );                      _reply.readException();                      _result = _reply.readString();                  }                  finally  {                      _reply.recycle();                      _data.recycle();                  }                  return  _result;              }          }          static  final  int  TRANSACTION_getCurrentPageUrl = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0 );      }      public  java.lang.String getCurrentPageUrl() throws  android.os.RemoteException; }

这个文件是Android SDK工具根据RemoteWebPage.aidl自动生成的,不要尝试着去修改该文件(改了也白改)。可以看到RemoteWebPage接口内包含了一个名为Stub的抽象的内部类,该类声明了RemoteWebPage.aidl中描述的方法getCurrentPageUrl(),并且还定义了少量的辅助方法Stub还定义了少量的辅助方法,尤其是asInterface(),通过它或以获得IBinder(当applicationContext.bindService()成功调用时传递到客户端的onServiceConnected())并且返回用于调用IPC方法的接口实例,更多细节参见Calling an IPC Method

4. 编写RemoteService.java

为了实现AIDL通信,必须在RemoteService类中实现RemoteWebPage.Stub接口,然后RemoteWebPage.Stbu内的相关方法,下面是RemoteService.java的代码:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package  com.braincol.aidl.service;   import  android.app.Service; import  android.content.Intent; import  android.os.IBinder; import  android.os.RemoteException; import  android.util.Log; /**   *   * @author briancol   * @description 提供service   *   */ public  class  RemoteService extends  Service {      private  final  static  String TAG = "RemoteService" ;      @Override      public  IBinder onBind(Intent intent) {          Log.i(TAG, "OnBind" );          return  new  MyBinder();      }        private  class  MyBinder extends  RemoteWebPage.Stub{          @Override          public  String getCurrentPageUrl() throws  RemoteException{              return  "http://www.cnblogs.com/hibraincol/" ;          }      } }

这样MyBinder就是一个RemoteWebPage.Stub类得子类,这样就可以通过RemoteService向客户端暴露AIDL接口了(MyBinder )。现在,如果客户端(比如一个Activity)调用bindService()来连接该服务端(RemoteService) ,客户端的onServiceConnected()回调函数将会获得从服务端(RemoteService )的onBind()返回的MyBinder对象。

在这里总结下服务端的编写流程:

    1. 创建.aidl文件:

        该文件(YourInterface.aidl)定义了客户端可用的方法和数据的接口

    2. 实现这个接口:

        Android SDK将会根据你的.aidl文件产生AIDL接口。生成的接口包含一个名为Stub的抽象内部类,该类声明了所有.aidl中描述的方法,你必须在代码里继承该Stub类并且实现.aidl中定义的方法。

相关推荐:Android中的跨进程通信的实现(一)——远程调用过程和aidl

(转载)http://foocoder.com android在设计理念上强调组件化,组件之间的依赖性很小。我们往往发一个intent请求就可以启动另一个应用的activity,或者一个你不知道在哪个进程的service,或者可以注册一个广播,只要有这个事件发生你都可以收到,又或者你可以

    3.向客户端公开服务端的接口:

        实现一个Service,并且在onBinder方法中返回第2步中实现的那个Stub类的子类(实现类)。

 

至此,服务端的代码就编写完成了。 下面开始编写客户端。

二、编写客户端代码

因为客户端和服务端不在同一个进程(应用程序)中,那么客户端也必须在src/目录下拥有和服务端同样的一份.aidl文件的拷贝(这样的同样是指:包名、类名、内容完全一样,可以把客户端的.aidl文件理解为代理),这样客户端将会通过这个RemoteWebPage.aidl文件在gen/目下生成和服务端一样的RemoteWebPage.java文件,然后客户端就可以通过该接口来访问服务端提供的方法了。下面是客户端的只要代码:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 package  com.braincol.aidl.client;   import  android.app.Activity; import  android.content.ComponentName; import  android.content.Context; import  android.content.Intent; import  android.content.ServiceConnection; import  android.os.Bundle; import  android.os.IBinder; import  android.os.RemoteException; import  android.util.Log; import  android.view.View; import  android.view.View.OnClickListener; import  android.widget.Button; import  android.widget.TextView; import  com.braincol.aidl.service.RemoteWebPage;   public  class  ClientActivity extends  Activity implements  OnClickListener {      private  final  static  String TAG= "ClientActivity" ;      TextView textView ;      Button btn_bind ;      Button btn_getAllInfo;      String actionName = "com.braincol.aidl.remote.webpage" ;      RemoteWebPage remoteWebPage= null ;      String allInfo = null ;      boolean  isBinded= false ;        @Override      public  void  onCreate(Bundle savedInstanceState) {          super .onCreate(savedInstanceState);          setContentView(R.layout.main);          textView = (TextView) findViewById(R.id.textView);          btn_bind = (Button) findViewById(R.id.btn_bind);          btn_getAllInfo = (Button)findViewById(R.id.btn_allinfo);            btn_getAllInfo.setEnabled( false );            btn_bind.setOnClickListener( this );          btn_getAllInfo.setOnClickListener( this );      }      @Override      protected  void  onPause(){          super .onPause();          Log.d(TAG, "onPause" );          if (isBinded){              Log.d(TAG, "unbind" );              unbindService(connection);             }      }      private  class  MyServiceConnection implements  ServiceConnection{            @Override          public  void  onServiceConnected(ComponentName name, IBinder service) {              Log.i(TAG, "建立连接..." );              remoteWebPage = RemoteWebPage.Stub.asInterface(service);              if (remoteWebPage== null ){                  textView.setText( "bind service failed!" );                     return ;              }              try  {                  isBinded= true ;                  btn_bind.setText( "断开" );                  textView.setText( "已连接!" );                  allInfo = remoteWebPage.getCurrentPageUrl();                  btn_getAllInfo.setEnabled( true );                 } catch  (RemoteException e) {                  e.printStackTrace();              }          }            @Override          public  void  onServiceDisconnected(ComponentName name) {              Log.i(TAG, "onServiceDisconnected..." );          }        }      MyServiceConnection connection = new  MyServiceConnection();        @Override      public  void  onClick(View v) {          if (v== this .btn_bind){              if (!isBinded){                  Intent intent  = new  Intent(actionName);                  bindService(intent, connection, Context.BIND_AUTO_CREATE);                             } else {                  Log.i(TAG, "断开连接..." );                  unbindService(connection);                  btn_getAllInfo.setEnabled( false );                     btn_bind.setText( "连接" );                  isBinded = false ;                  textView.setText( "已断开连接!" );              }          } else  if (v== this .btn_getAllInfo){              textView.setText(allInfo);          }        } }

 

上面的代码中类MyServiceConnection实现了ServiceConnection类,在MyServiceConnection类的onServiceConnected方法中通过RemoteWebPage.Stub.asInterface(service)获取到远端服务端的RemoteWebPage接口对象remoteWebPage,这样就可以通过remoteWebPage.getCurrentPageUrl()获取到服务端提供的相关的信息。客户端通过bindService()方法绑定远程服务端,通过unbindService()断开连接。连接客户端的相关的代码为:

1 2 Intent intent  = new  Intent(actionName); bindService(intent, connection, Context.BIND_AUTO_CREATE);

客户端就是通过actionName(com.braincol.aidl.remote.webpage)来找到服务端。

下面总结下客户端的编写流程:

    1. 在 src/ 目录下包含.adil文件。

    2. 声明一个IBinder接口(通过.aidl文件生成的)的实例。

    3. 实现ServiceConnection.

    4. 调用Context.bindService()绑定你的ServiceConnection实现类的对象(也就是远程服务端)。

    5. 在onServiceConnected()方法中会接收到IBinder对象(也就是服务端),调用YourInterfaceName.Stub.asInterface((IBinder)service)将返回值转换为YourInterface类型。

    6. 调用接口中定义的方法,并且应该总是捕获连接被打断时抛出的DeadObjectException异常,这是远端方法可能会抛出唯一异常。

    7. 调用Context.unbindService()方法断开连接。

 

下面给出本示例源码的下载地址:

http://download.csdn.net/detail/Niosm/3593187

在附一个稍微复杂点的例子(通过IPC传递Parcelable对象):

http://download.csdn.net/detail/Niosm/3593376

原文

关于AIDL的介绍及实现步骤等请参考: http://www.cnblogs.com/hibraincol/archive/2011/09/06/2169325.html 本篇文章只是用一个实例来分析AIDL的实现。 本示例实现的是:AIDL客户端通过AIDL接口

------分隔线----------------------------