在aidl中也可以自定义类型。
写两个aidl文件:
IBookManager.aidl
interface IBookManager {
void add(in Book book);
List<Book> getBookList();
}
在aidl中声明Book,Book.aidl
parcelable Book;
在服务端,通过Binder返回远程服务对象Stub。而这个Stub实现了aidl接口中的内容并继承Binder。
而在客户端,通过绑定一个远程服务,在服务连接成功后,得到这个远程服务对象Stub。用一个aidl接口去引用。
这就是利用Service进行IPC的大概内容。
观察aidl文件编译后的java文件的内容:
package com.asule.cn;
public interface IBookManager extends android.os.IInterface{
//我们在aidl接口
public java.util.List<com.asule.cn.Book> getBookList() throws android.os.RemoteException;
public void add(com.asule.cn.Book book) throws android.os.RemoteException;
//-----------------Stub----------------------->
public static abstract class Stub extends android.os.Binder implements com.asule.cn.IBookManager{
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
//binder的唯一标识
private static final java.lang.String DESCRIPTOR = "com.asule.cn.IBookManager";
public Stub(){
this.attachInterface(this, DESCRIPTOR);
}
public static com.asule.cn.IBookManager asInterface(android.os.IBinder obj){
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.asule.cn.IBookManager))) {
return ((com.asule.cn.IBookManager)iin);
}
return new com.asule.cn.IBookManager.Stub.Proxy(obj);
}
//返回Stub句柄
@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_getBookList:{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.asule.cn.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook:{
data.enforceInterface(DESCRIPTOR);
com.asule.cn.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.asule.cn.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
//-----------------Proxy----------------------->
//Stub的内部类Proxy
private static class Proxy implements com.asule.cn.IBookManager{
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;
}
//
@Override
public java.util.List<com.asule.cn.Book> getBookList() throws android.os.RemoteException{
//
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.asule.cn.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.asule.cn.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void add(com.asule.cn.Book book) throws android.os.RemoteException{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
//<-----------------Proxy-----------------------
}
//<-----------------Stub-----------------------
}
aidl接口和aidl文件中的内容一致。有两个抽象方法,这就是在aidl文件中定义的方法。
可以发现Stub实现了aidl接口,继承自Binder。
Stub中的两个final类型的静态变量
TRANSACTION_getBookList和TRANSACTION_add
DESCRIPTOR:Stub的唯一标识
先前说,在客户端通过asInterface,把获取的Binder对象转换为Stub远程服务实例,通过一个aidl的接口引用。
但asInterface返回的却不一定是Stub。
在此方法中,会判断客户端和服务端是否位于同一个进程,如果是,返回的是stub对象本身,否则返回的是Stub的Proxy。
在代理模式中,代理Proxy和真实对象往往实现同一个接口,代理对象握有真实对象的引用,以便操作真实对象。
Proxy同样实现了aidl接口,把Stub对象实例传递到Proxy中。
当客户端调用getBookList,实际调用的是Proxy中的getBookList。在方法中,
声明了Parcel的输入对象_data,Parcel的输出对象_reply。
调用transact方法来发起RPC(远程过程调用)请求,同时当前线程挂起,然后服务端的Stub的onTransact执行。(onTransact运行在Binder线程池中)
在onTransact中通过code判断是哪个方法执行,然后就会执行Stub的getBookList方法。当方法执行完毕后,会把结果写入到reply中,返回true表示客户端的远程调用成功,否则失败。
而直到RPC结束,客户端的线程才继续执行,从_reply中取出RPC的返回结果,最后返回_reply中的数据。
当足够了解了Binder,其实也可以不借助aidl工具。写aidl的目的只是为了更方便更快速的实现Binder。
不写aidl的话,需要手写接口,Stub,Proxy。在客户端同样也不需要写aidl,直接拷贝手写的java文件。