AIDL即Android Interface Definition Language,用于实现Android进程间通信(IPC)。
两个App间通信的代码实现
1.定义AIDL文件
由于进程之间的通信信息需要双向转换,所以android采用代理类在背后实现了信息的双向转换,代理类由android编译器生成,对开发人员来说是透明的。
1 2 3 4 5 6 7
| package com.lcodecore.myapplication; interface IRemoteService { void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); }
|
对于非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。
1 2 3 4
| interface IMyService { void savePersonInfo(in Person person); List<Person> getAllPerson(); }
|
编译后会自动生成IRemoteService.java文件。
AIDL定义规则:
- 接口名和aidl文件名相同。
- 接口和方法前不用加访问权限修饰符public,private,protected等,也不能用final,static。
- Aidl默认支持的类型包话java基本类型(int、long、boolean等)和(String、List、Map、CharSequence,使用这些类型时不需要import声明。对于List和Map中的元素类型必须是Aidl支持的类型。 如果使用自定义类型作为参数或返回值,自定义类型必须实现Parcelable接口。
- 自定义类型和AIDL生成的其它接口类型在aidl描述文件中,应该显式import,即便在该类和定义的包在同一个包中。
- 在aidl文件中所有非Java基本类型参数必须加上in、out、inout标记,
以指明参数是输入参数、输出参数还是输入输出参数。
- Java原始类型默认的标记为in,不能为其它标记。
2.定义Service,在onBind方法中返回IRemoteService.Stub的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class DDService extends Service { @Override public void onCreate() { super.onCreate(); System.out.println("DDService onCreate........" + "Thread: " + Thread.currentThread().getName()); } @Override public IBinder onBind(Intent arg0) { return mBinder; } private final IRemoteService.Stub mBinder = new IRemoteService.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { System.out.println("Thread: " + Thread.currentThread().getName()); System.out.println("basicTypes aDouble: " + aDouble +" anInt: " + anInt+" aBoolean " + aBoolean+" aString " + aString); } }; }
|
Stub继承自Binder,即远程服务特别在返回了实现了AIDL接口的IBinder对象。
然后在manifest.xml文件中声明:
1 2 3 4 5 6
| <service android:name=".DDService" android:process=":remote"> <intent-filter> <action android:name="android.intent.action.AIDLService" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </service>
|
android:process=”:remote”,代表在应用程序里,当需要该service时,会自动创建新的进程。而如果是android:process=”remote”,没有“:”号的,则创建全局进程,不同的应用程序共享该进程。
服务器端的代码就完成了。
3.新建客户端工程,定义一个与服务器端路径相同的IRemoteService.aidl文件
4.实现ServiceConnection并连接服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { IRemoteService remoteService = IRemoteService.Stub.asInterface(service); try { remoteService.basicTypes(1,1,true,1f,1d,"测试"); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) {} }; Intent intent = new Intent(android.intent.action.AIDLService); bindService(conn);
|
内部原理
Android进程间通信需要使用Binder机制,Binder作为一种进程间通信机制,负责提供远程调用的功能(RPC),它的系统组件主要包括四种:Client, Server, ServiceManager, Binder Driver。
- Client, Server, ServiceManager运行在系统的用户态,而Binder Driver运行在内核态。
- 为了完成Client端到Server端的通信任务,用户空间的需要操作Binder Driver提供的/dev/binder文件来完成交互。
- ServiceManager负责管理Server并向Client端提供一个Server的代理接口(proxy)。通过代理接口中定义的方法,Client端就可以使用Server端提供的服务了。
整个过程为:
- Client端调用代理接口的方法,将Client的参数打包为parcel对象发送给内核空间中BinderDriver;
- Server端读取到BinderDriver中的请求数据,将parcel对象解包并处理;
- 处理好后,将处理结果打包返回给BinderDriver,再交给Client端。
参考博客
从AIDL开始谈Android进程间Binder通信机制