通过此文记录以下自己在使用AIDL时的一些理解。
在Android Studio中首先定义.aidl文件:
package com.github.androidfdm.service.aidl;
interface ISampleAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
String sample(int str);
}
紧接着Make Project,AS会自动生成对应的AIDL类文件:
package com.github.androidfdm.service.aidl;
public interface ISampleAidlInterface extends android.os.IInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
public java.lang.String sample(int str) throws android.os.RemoteException;
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.github.androidfdm.service.aidl.ISampleAidlInterface {
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_sample = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
private static final java.lang.String DESCRIPTOR = "com.github.androidfdm.service.aidl.ISampleAidlInterface";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.github.androidfdm.service.aidl.ISampleAidlInterface interface,
* generating a proxy if needed.
*/
public static com.github.androidfdm.service.aidl.ISampleAidlInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.github.androidfdm.service.aidl.ISampleAidlInterface))) {
return ((com.github.androidfdm.service.aidl.ISampleAidlInterface) iin);
}
return new com.github.androidfdm.service.aidl.ISampleAidlInterface.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_basicTypes: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0 != data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
case TRANSACTION_sample: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _result = this.sample(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.github.androidfdm.service.aidl.ISampleAidlInterface {
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;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean) ? (1) : (0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public java.lang.String sample(int str) 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);
_data.writeInt(str);
mRemote.transact(Stub.TRANSACTION_sample, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
}
}
注意到,生成的类(.java)文件中包含了我们在.aidl文件中定义的方法。附带的还生成了两个内部的静态类。一个是Stub(抽象类),该内部静态类继承自Binder类,并且实现了我们定义的.aidl文件中的接口。
另一个是Proxy,其构造函数接收一个Stub对象并是实现了.aidl文件中的接口,并实现了其中的方法。拿sample(int str)函数来说,这个实现从代码中可以看出obtain了两个Parcel:_data和_reply分别用来传递参数和返回值。之后将接收到的参数写进_data这个Parcel紧接着调用Stub的transact方法。再回到Stub中,transact方法最终会调用到Stub中的onTransact方法,通过第一个参数来区分我们具体调用的哪个方法。然后onTransact方法会从刚刚的_data中读取出来数据调用本身的sample(int str)方法,然后将返回值写到_reply中。再回到Proxy中,调用完Stub(mRemote)中的对应方法后,从_reply中读取到返回值然后返回。整个调用过程就是如此。
但目前还有些不解的是,在Proxy(client)中调用的函数是如何在Service(server)中执行的,从上面的过程来看Proxy只是传递了参数到Parcel中,便可以调用Binder的transact方法让server执行相应的函数?答:通过系统调用调用到binder驱动的transact()函数,然后又通过某种消息机制调用server的onTransact()
接着上面的步骤,再定义个Service,并在manifast文件中指定其android:process属性.
public class SampleAidlService extends SampleService {
private ISampleAidlInterface.Stub aidlBinder = new ISampleAidlInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
L.e(this.getClass().getSimpleName(), "Im aidl binder!");
}
@Override
public String sample(int str) throws RemoteException {
switch (str) {
case 0:
return "Im aidl binder!";
default:
return null;
}
}
@Override
public String toString() {
return "Im aidl binder!";
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
L.e(this.getClass().getSimpleName(), "onBind AIDL");
return aidlBinder;
}
}
可以看到,我们在OnBind()方法中返回的是那个叫做Stub(extends Binder)的抽象内部类的对象!
之后在ServiceConnection中获取返回的Binder:
aidlConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
ISampleAidlInterface binder = ISampleAidlInterface.Stub.asInterface(service);
try {
L.e(MainActivity.this.getClass().getSimpleName(), binder.sample(0));
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
然后就可以利用这个代理类的对象愉快的进行通信了。
网友评论