意义:

由于每个应用进程都有自己的独立进程空间,在android平台上,一个进程通常不能访问另一个进程的内存空间,而我们经常需要夸进程传递对象,就需要把对象分解成操作对象可以理解的基本单元,并且有序的通过进程边界。

定义:

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

说明以及实现流程:

AIDL接口和普通的java接口没有什么区别,只是扩展名为.aidl,保存在src目录下,如果其他应用程序需要IPC,则也需要在src目录下创建同样的AIDL文件,创建完毕之后,通过ADT工具,会在工程的gen目录下生成相对应的.java文件。

一般实现两个进程之间的通信需要实现下面几个步骤

(1)在Eclipse的android工程目录下面创建一个.aidl扩展名的文件,语法和java定义接口的语法差不多,不过需要自己手动import对应的包名。(比如需要用到list集合,则需要import java.util.List;)

(2)如果aidl文件符合规范,ADT工具会帮助编译器在gen目录下生成相对应的.java文件。

(3)需要继承实现一个服务类,跨进程调用的基础。

(4)在service端实现AIDL接口,如果有回调则在client端实现callback的AIDL接口。

(5)在AndroidManifest.xml注册service。

注意:

实现AIDL,我们需要注意以下五点

1)AIDL只支持接口方法,不能公开static变量。

2)AIDL接口方法如果有参数,则需要注意in、out、inout的使用规则,对于基本数据类型,默认是in类型,可以不需要添加声明,非基本可变对象需要在变量名之前添加方法类型

in表示输入参数,调用者把值传递给使用者使用。

out表示输出参数,调用者把容器传递给使用者填充,然后自己使用处理。

inout标书输入输出参数,传送相应的值并接收返回。

列举一个out的使用例子:
服务端传参数给客户端,客户端填充,服务端调用完之后,可以读取到客户端填写的内容,具体的例子后面将给出。

3)AIDL定义的接口名必须和文件名一致。

4)oneway表示用户请求相应功能时不需要等待响应可直接调用返回,非阻塞效果,该关键字可以用来声明接口或者声明方法,如果接口声明中用到了oneway关键字,则该接口声明的所有方法都采用oneway方式。

5)AIDL传递非基本可变长度变量(非final对象),需要实现parcelable接口。具体请看http://my.oschina.net/zhoulc/blog/172163

实例:

下面列举一个例子,主要实现客户端调用服务端然后回调回来,具体实现功能改变客户端的文字和图片显示,这个例子暂时效果是图片的更改直接使用客户端已经准备好的图片,接下来几篇博客会基于这个功能完善,到达服务端可以发送文字、图片、文件句柄(I/O流),并且直接由服务端通过方法名称直接调用客户端方法,客户端只需要注册对应的view并且提供相应的方法给服务端使用,后面的两部的完善主要用到反射和重写MemoryFile(达到parcelable序列化效果)来实现。

1)首先按照我们上面的步骤需要创建aidl文件,分别创建调用和回调的aidl文件,为了阐述更详细一些,博主把parcelable对象也添加进去,仅仅作为测试。

IMyAidlService.aidl主要由服务端实现客户端调用

package com.zlc.aidl;import com.zlc.aidl.DemoParcelable;import com.zlc.aidl.AIDLCallback;interface IMyAidlService{void registerClient(AIDLCallback cb);//注册回调void saveDemoInfo(in DemoParcelable demo);//实际调用方法}
AIDLCallback.aidl主要由客户端实现,服务端调用
package com.zlc.aidl;import com.zlc.aidl.DemoParcelable;import java.util.List;interface AIDLCallback {int returnResult(out List<DemoParcelable> list,int a);//回调给客户端void testMethod(out Bundle params);//用来测试参数in/out的使用}
DemoParcelable.aidl声明传递对象
package com.zlc.aidl;parcelable DemoParcelable;

补充一点:out和in参数区别其实很明显我们直接查看adt生成在gen目录下对应的java文件就可以看出区别:当是out参数的时候是执行完之后从parcel对象读取值,而in参数时是写到parcel对象里面传过去。
我们看下当testMethod分别是out和in修饰时生成的文件
当时out的时候是从parcel对象里面读数据

mRemote.transact(Stub.TRANSACTION_testMethod, _data, _reply, 0);_reply.readException();if ((0!=_reply.readInt())) {params.readFromParcel(_reply);}
当时in的时候是从parcel对象里面取数据
if ((params!=null)) {_data.writeInt(1);params.writeToParcel(_data, 0);}else {_data.writeInt(0);}mRemote.transact(Stub.TRANSACTION_testMethod, _data, _reply, 0);_reply.readException();

2)实现一个服务类用来实现进程之间通信MyAidlService.java,贴出部分代码,详细代码会在后面上传。

@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubLog.d(TAG, "MyAidlService onBind");return mBinder;}private final IMyAidlService.Stub mBinder = new IMyAidlService.Stub() {private AIDLCallback cb;@Overridepublic void saveDemoInfo(DemoParcelable demo) throws RemoteException {if (demo != null) {if ("meinv1".equals(demo.getDemo_name())) {demo.setDemo_name("meinv2");}list.add(demo);Log.d(TAG, "saveDemoInfo list.size = " + list.size() + " list = " + list);cb.returnResult(list, 5);Bundle params = new Bundle();cb.testMethod(params);int width = params.getInt("width", 0);int height = params.getInt("height", 0);Log.d(TAG, "width = " + width + " height = "+height);}}@Overridepublic void registerClient(AIDLCallback cb) throws RemoteException {cb.asBinder().linkToDeath(new DeathRecipient() {@Overridepublic void binderDied() {try {Log.i(TAG, "[ServiceAIDLImpl]binderDied.");} catch (Throwable e) {}}}, 0);}};
3)实现客户端连接并且实现callback方法
private ServiceConnection mRemoteConnection = new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stubLog.d(TAG, "onServiceDisconnected");}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// TODO Auto-generated method stubLog.d(TAG, "onServiceConnected");mRemoteService = (IMyAidlService) IMyAidlService.Stub.asInterface(service);if(mRemoteService != null)Log.d(TAG, "onServiceConnected success");}};……btn.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubString actionName = "com.zlc.aidl.server.MyAidlService";Intent intent = new Intent(actionName);boolean ret = bindService(intent, mRemoteConnection,Context.BIND_AUTO_CREATE);Log.d(TAG, " ret ?=" + ret);if (ret) {new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubtry {DemoParcelable demo = new DemoParcelable();List<String> list = new ArrayList<String>();list.add("like dance");demo.setDemo_id((Integer) img.getTag());demo.setDemo_name("meinv1");demo.setDemo_list(list);mRemoteService.registerClient(callback);mRemoteService.saveDemoInfo(demo);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}).start();}}});}……private final AIDLCallback callback = new AIDLCallback.Stub() {@Overridepublic int returnResult(List<DemoParcelable> list, int a)throws RemoteException {if (list != null)Log.d(TAG, "list.size = " + list.size()+"    a="+a);for (DemoParcelable demoParcelable : list) {doFresh(demoParcelable);}return 0;}@Overridepublic void testMethod(Bundle outParams) throws RemoteException {// TODO Auto-generated method stubif (outParams != null) {                outParams.putInt("width", 11);                outParams.putInt("height", 12);            }}};

4)在androidManifest.xml里面注册service服务。

注意一点:android:process=":remote",代表在应用程序里,当需要该service时,会自动创建新的进程。而如果是android:process="remote",没有“:”分号的,则创建全局进程,不同的应用程序共享该进程。
通过ps直接看pid进程号就可以看出。
让应用的组件在一个单独的进程中运行,如果带冒号: ,则创建一个专属于当前进程的进程,如果不带冒号,需要使用标准的命名规范命名进程名,例如com.xxx.xxx.xxx,而且该进程是全局共享的进程,即不同应用的组件都可以运行于该进程。
这可以突破应用程序的24M(或16M)内存限制。
总之,使用带:remote的属性的进程id pid不同,父进程ID PPID是一样的。而使用不带冒号的remote则会创建两个完全独立的进程。

贴上测试案例图:
Android之AIDL进程之间的通信Android之AIDL进程之间的通信

最后贴上代码:aidl测试case.rar

更多相关文章

  1. Android多进程使用及其带来的问题
  2. /2015/6/12/ BiliBili Android 新客户端与底部导航 Tabs
  3. Android 客户端与服务器交互
  4. Android进程间通信IPC机制Binder
  5. Android应用中通过AIDL机制实现进程间的通讯实例
  6. Android studio 下的aidl编程实现Android的夸进程间通信
  7. Android 4.1模拟器访问服务器接口
  8. Android多线程系统概述(sundy深入浅出)之进程和线程

随机推荐

  1. 欢迎下载科幻世界iPhone、iPad、Android
  2. android控件属性
  3. Android 用户界面
  4. Logger详解(二)
  5. Android 数据导出之Excle jxl.jar
  6. 关于android:background="@drawable/bg_p
  7. Android网络检测
  8. Basics of Android : Part IV – Android
  9. 关于android studio 出现Error:Execution
  10. android framework java层服务 分析