AS只有build之后才能将.aidl文件转换为.java文件
AILD(只支持方法,不支持静态变量)语法
基本类型:
1)Java的4类8种基本类型。byte,short(因为Parcel不支持short,而AIDL的底层需要Parcel传数据,所以AIDL也不支持short),int,long,float,double,char.(基本类型默认且只能是in);
2)String,Charsequence;
3)List,map(底层是靠arrayList,HashMap实现,所以发送换是接收得要是这2种)
4)Parcelable接口的实现类;
除了1)不标数据流向之外,2),3),7)作为方法参数需要表示数据的流向.数据流向用in,out,inout表示.
in--->表示数据由客户端流向服务端,服务端的修改不会同步到客户端--->_arg0 = data.readInt();
out--->表示数据由服务端流向客户端,服务端的改变会同步到客户端--->服务端会新建一个空对象,并将服务端对此对象的修改写给reply,传给客户端。
_arg0 = new com.example.iadlserver.Person();
java.util.List<java.lang.String> _result = this.basicTypes(_arg0);
reply.writeNoException();
reply.writeStringList(_result); |
if ((0!=data.readInt())) {
_arg0 = com.example.iadlserver.Person.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
java.util.List<java.lang.String> _result = this.basicTypes(_arg0);
reply.writeNoException();
reply.writeStringList(_result); |
AIDL具体实现:
服务端:
定义AIDL接口,Parcelable接口的实现类需要import包,即使该实现类和aidl文件在同一个包。因为AIDL在aidl文件夹下,java文件在java文件夹下,AS的默认gradle在java文件夹,将实现Parcelable接口的java文件放在aidl文件夹下,则AS不能gradle,实现Parcelable接口的java文件放在java文件夹下,则aidl不能使用。为了解决这种问题。解决方案有2种:
解决方案一:将实现Parcelable接口的java文件放在java文件夹下,但在aidl文件夹定义一个该实现类的aidl文件,并用parcelable声明该类。
解决方案二:将实现Parcelable接口的java文件放在aidl文件夹下,改变AS默认的gradle方式,找到build。gradle文件,在Android{}中添加该语句
服务端应该开启一个Service去接收客户端的请求。实现该AIDL接口的.Stub对象
在该实现类中写服务端的处理流程。
在onbind()方法中返回。
客户端:将服务端的AIDL文件拷贝到客户端,若有Parcelable接口的实现类,按照服务端的方法操作。客户端启动Service,从Android5.0之后,Service只能通过显示启动,绑定的服务,必须在onDestroy()中解绑服务。
这样就可以在客户端听过mBind操作服务端的方法了。
AIDL源码分析
aidl接口的.java文件的整体框架,包括一个stub和在aidl接口中声明的方法.
IMyAidlInterface.Stub.asInterface(iBinder)的返回值是一个Proxy(代理),关键代码如下:
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.example.iadlserver.IMyAidlInterface))) { return ((com.example.iadlserver.IMyAidlInterface)iin); } return new com.example.iadlserver.IMyAidlInterface.Stub.Proxy(obj);若客户端的 iBinder和服务端在同一个进程,则返回Stub对象 。否则,返回代理。
Proxy是在内部类Stub中的一个类,Stub的主要方法:
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags);
第一个参数表示某个方法,aidl将方法编号,根据编号执行不同的代码。data,reply封装客户端传递的参数和返回给客户端的参数。
返回值表示客户端的请求能否成功。
测试数据流向:
客户端:代码:
Person person=new Person(24,"zhangce"); Person person2=new Person(24,"zhangce"); Person person3=new Person(24,"zhangce"); try { Log.i(TAG, "out person"+person.toString()+"in person"+person2.toString()+"inout person"+person3.toString()); mBind.basicTypes(person,person2,person3); Log.i(TAG, "out person"+person.toString()+"in person"+person2.toString()+"inout person"+person3.toString()); } catch (RemoteException e) { e.printStackTrace(); }
结果:MainActivity:out person Person{userName='zhangce',userId=24} in person Person{userName='zhangce',userId=24}inout person Person{userName='zhangce',userId=24}
MainActivity:out person Person{userName=null,userId=0} in person Person{userName='zhangce',userId=24}inout person Person{userName='zhangce',userId=23}
服务端:
代码 :
Log.i(TAG, "out person"+person.toString()+"in person"+person2.toString()+"inout person"+person3.toString()); person.setUserId(23); person2.setUserId(23); person3.setUserId(23); Log.i(TAG, "out person"+person.toString()+"in person"+person2.toString()+"inout person"+person3.toString());
结果:
MainActivity:out person Person{userName=null,userId=0} in person Person{userName='zhangce',userId=24}inout person Person{userName='zhangce',userId=24}
MainActivity:out person Person{userName=null,userId=23} in person Person{userName='zhangce',userId=23}inout person Person{userName='zhangce',userId=23}