在使用跨进程通信时(IPC),需要编写大量代码,且很多代码都是模板式的,所以Android定义了AIDL(Android Interface Definition Language)文件来简化 IPC 操作。AIDL的使用流程如下:
- 创建AIDL文件,并在其中定义业务接口
- 编译,ADT会根据AIDL文件自动生成Java文件
- 服务端实现AIDL生成的业务接口,并通过
asBinder
方法返回 - 客户端通过
binderService
绑定服务 - 客户端在收到
onServiceConnected
回调时,通过asInterface
方法将回调的IBinder
对象转化为业务接口 - 客户端调用业务接口实现 IPC 通信
类图
AIDL文件
package com.whf.demolist;
interface IRemote {
int getCount();
void setCount(int count);
}
AIDL生成类
package com.whf.demolist.binder;
public interface IRemote extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements IRemote {
/**
* Binder的唯一标识,一般使用当前Binder的类名
*/
private static final String DESCRIPTOR = "com.whf.demolist.IRemote";
public Stub() {
//将自己和DESCRIPTOR存储到Binder对象中mOwner和mDescriptor成员
this.attachInterface(this, DESCRIPTOR);
}
/**
* 用于将服务端的Binder转换成客户端所需要的AIDL接口类型的对象,这种转换区分进程,如果客户端和服务端处同 一个进程,那么此方法返回的就是服务端的Stub本身,否则返回的是系统封装后的Stub.proxy对象
*/
public static IRemote asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
//从Binder中查询对应DESCRIPTOR,与前面的attachInterface相对应
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof IRemote))) {
return ((IRemote) iin);
}
return new Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
/**
* 该方法运行在服务端中的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理
* @param code 服务端通过改参数可以确定客户端所请求的目标方法是什么
* @param data 目标方法所需要的参数(如果目标方法有参数的话)
* @param reply 方法执行完成后,其返回值写入到该参数中
* @return 返回false代表客户端请求失败
*/
@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_getCount: {
//校验是否合法
data.enforceInterface(DESCRIPTOR);
int _result = this.getCount();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_setCount: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
this.setCount(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements IRemote {
//BinderProxy对象,Binder的代理,用于多进程通信时向Binder写入数据
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public int getCount() throws android.os.RemoteException {
//创建所需要的输入型Parcel对象(从parcel池中获取,如果池中没有了就新建)
android.os.Parcel _data = android.os.Parcel.obtain();
//创建所需要的输出型Parcel对象
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
//将该方法的参数写入_data中 ( 该方法无参数,所以不用写,详见setCount()方法 )
_data.writeInterfaceToken(DESCRIPTOR);
//发起RPC(远程过程调用)请求,实际调用的是onTransact方法,并且当前线程挂起,直至RPC过程返回,当前线程继续执行
mRemote.transact(Stub.TRANSACTION_getCount, _data, _reply, 0);
//从_reply中取出RPC过程的返回结果
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void setCount(int count) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
//将该方法的参数写入_data中
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(count);
mRemote.transact(Stub.TRANSACTION_setCount, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
//方法的唯一标识
static final int TRANSACTION_getCount = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_setCount = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public int getCount() throws android.os.RemoteException;
public void setCount(int count) throws android.os.RemoteException;
}
Service端实现
public class AidlService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return remoteStub ;
}
//服务端实现业务接口
private IRemote.Stub remoteStub = new IRemote.Stub() {
@Override
public int getCount() throws RemoteException {
return count;
}
@Override
public void setCount(int count) throws RemoteException{
RemoteService.this.count = count;
}
};
}
Clinet端使用
//ClientActivity中
IRemote remoteService;
bindService(bindServiceIntent, connection, Context.BIND_AUTO_CREATE);
//ServiceConnection
public ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取 Service 端引用
ClientActivity.this.remoteService = IRemote.Stub.asInterface(service);
//设置死亡监听
try {
service.linkToDeath(deathRecipient,0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
ClientActivity.this.remoteService = null;
}
};
/**
* 死亡监听,当Binder连接断裂(称之为Binder死亡),会导致远程调用失败,更为关键的是我们并不知道Binder已经
* 断开连接,那么客户端的功能就会一直受影响,所以可以通过设置Binder的死亡监听,当Binder死亡时就会收到通知
* 另外也可以同过Binder的 isBinderAlive 方法去主动判断Binder是否死亡
*/
private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (remoteService==null){
return;
}
remoteService.asBinder().unlinkToDeath(deathRecipient,0);
remoteService = null;
//重新绑定远程服务
bindRemoteService();
}
};
定向Tag
所有的非基本参数都需要一个定向Tag来指出数据流通的方式,不管是in
, out
, 还是 inout
,基本参数的定向Tag默认是并且只能是 in。
- in :数据只能由客户端流向服务端
- out:数据只能由服务端流向客户端
- inout:数据可在服务端与客户端之间双向流通