支持的数据类型
1、八种基本数据类型:byte、char、short、int、long、float、double、boolean
2、String,CharSequence
3、实现了Parcelable接口的数据类型
4、List 类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
5、Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
定向Tag
定向Tag。定向Tag表示在跨进程通信中数据的流向,用于标注方法的参数值,分为 in、out、inout 三种。
其中 in 表示数据只能由客户端流向服务端,
out 表示数据只能由服务端流向客户端,
而 inout 则表示数据可在服务端与客户端之间双向流通。
此外,如果AIDL方法接口的参数值类型是:基本数据类型、String、CharSequence或者其他AIDL文件定义的方法接口,那么这些参数值的定向 Tag 默认是且只能是 in,所以除了这些类型外,其他参数值都需要明确标注使用哪种定向Tag。定向Tag具体的使用差别后边会有介绍
具体使用
https://github.com/fengyuehan/Test/tree/master/service
下面重点讲定向Tag。
首先在aidl文件中创建几个方法,
interface IRemoteBookBinder {
void addBookIn(in BookBean bookBean);
void addBookOut(out BookBean bookBean);
void addBookInOut(inout BookBean bookBean);
List<BookBean> getBookList();
}
要了解其通信原理,得先了解几个概念:
IBinder:代表跨进程传输的能力。只要实现了这个接口,就能将这个对象进行跨进程传递;这是驱动底层支持的;在跨进程数据流经驱动的时候,驱动会识别IBinder类型的数据,从而自动完成不同进程Binder本地对象以及Binder代理对象的转换。
IInterface:IBinder负责数据传输,而client与server调用的契机就是继承了IInterface的aidl里面的类。我们写好aidl文件之后,build成功之后会生成一个java文件。然后通过stub和proxy去实现该接口。这样客户端就可以调用服务端的方法。
public interface IRemoteBookBinder extends android.os.IInterface
{
/** Default implementation for IRemoteBookBinder. */
public static class Default implements com.example.service.IRemoteBookBinder
{
@Override public void addBookIn(com.example.service.bean.BookBean bookBean) throws android.os.RemoteException
{
}
@Override public void addBookOut(com.example.service.bean.BookBean bookBean) throws android.os.RemoteException
{
}
@Override public void addBookInOut(com.example.service.bean.BookBean bookBean) throws android.os.RemoteException
{
}
@Override public java.util.List<com.example.service.bean.BookBean> getBookList() throws android.os.RemoteException
{
return null;
}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
Stub:binder的本地类
Proxy:binder的代理类。
Stub和Proxy在客户端和服务端同时都存在,而不是Proxy存在客户端,stub存在服务端。一般是从Proxy开始请求,Stub去接收处理请求。
在服务端我们RemoteBookBinderImpl去继承Stub,表明RemoteBookBinderImpl实例具有代表跨进程传输的能力。然后通过onBind方法返回。
public class RemoteBookBinderImpl extends IRemoteBookBinder.Stub{
private List<BookBean> bookBeans = new ArrayList<>();
@Override
public void addBookIn(BookBean bookBean) throws RemoteException {
Logger.i("------------------------服务端修改前的数据----------------------");
Logger.i("" + bookBean.toString() + currentProgressAndThread());
Logger.i("--------------------------------------------------------------");
bookBean.bookAuthor = "zzf";
bookBeans.add(bookBean);
Logger.i("------------------------服务端修改后的数据----------------------");
Logger.i("" + bookBean.toString() + currentProgressAndThread());
Logger.i("--------------------------------------------------------------");
}
@Override
public void addBookOut(BookBean bookBean) throws RemoteException {
Logger.i("------------------------服务端修改前的数据----------------------");
Logger.i("" + bookBean.toString() + currentProgressAndThread());
Logger.i("--------------------------------------------------------------");
bookBean.bookAuthor = "zzf";
bookBeans.add(bookBean);
Logger.i("------------------------服务端修改后的数据----------------------");
Logger.i("" + bookBean.toString() + currentProgressAndThread());
Logger.i("--------------------------------------------------------------");
}
@Override
public void addBookInOut(BookBean bookBean) throws RemoteException {
Logger.i("------------------------服务端修改前的数据----------------------");
Logger.i("" + bookBean.toString() + currentProgressAndThread());
Logger.i("--------------------------------------------------------------");
bookBean.bookAuthor = "zzf";
bookBeans.add(bookBean);
Logger.i("------------------------服务端修改后的数据----------------------");
Logger.i("" + bookBean.toString() + currentProgressAndThread());
Logger.i("--------------------------------------------------------------");
}
@Override
public List<BookBean> getBookList() throws RemoteException {
if (ListUtils.notEmpty(bookBeans)) {
Logger.i("-------- 书本总数: " + bookBeans.size() + " ------------");
for (BookBean bookBean : bookBeans) {
Logger.i("BookList => " + bookBean);
}
Logger.i("-----------------------------------");
}
return bookBeans;
}
}
public IBinder onBind(Intent intent) {
remoteBookBinder = new RemoteBookBinderImpl();
return remoteBookBinder;
}
此时需要在客户端获取到这个实例,这样就建立起连接。
当我们在客户端bindService的时候,会传入bindConnection参数,当连接成功的时候,会将service通过回调返回过来,然后通过调用asInterface()去判断。
bindService(intent, bindConnection, Service.BIND_AUTO_CREATE);
private ServiceConnection bindConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iRemoteBookBinder = IRemoteBookBinder.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
iRemoteBookBinder = null;
}
};
下面看下asInterface():
public static com.example.service.IRemoteBookBinder asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.service.IRemoteBookBinder))) {
return ((com.example.service.IRemoteBookBinder)iin);
}
return new com.example.service.IRemoteBookBinder.Stub.Proxy(obj);
}
如果是同一个进程,则返回当前对象,如果不是同一个进程,则放回去代理对象。
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
在这里通过静态代理的方式。
然后在客户端调用定义的aidl里面的方法,与服务端进行通信。
// addBookIn
Logger.i("-------- addBookIn() ------------------------");
int nextIntIn = RandomUtils.randomInt(10000);
BookBean bookBeanIn = new BookBean("书名-" + nextIntIn, "作者-" + nextIntIn,
(RandomUtils.randomInt(10000) + 10000) / 100d);
Logger.i(RemoteBinderService.SERVICE_NAME + " addBookIn() before info:" + bookBeanIn.toString());
iRemoteBookBinder.addBookIn(bookBeanIn);
Logger.i(RemoteBinderService.SERVICE_NAME + " addBookIn() after info:" + bookBeanIn.toString());
// addBookOut
Logger.i("-------- addBookOut() ------------------------");
int nextIntOut = RandomUtils.randomInt(10000);
BookBean bookBeanOut = new BookBean("书名-" + nextIntOut, "作者-" + nextIntOut,
(RandomUtils.randomInt(10000) + 10000) / 100d);
Logger.i(RemoteBinderService.SERVICE_NAME + " addBookOut() before info:" + bookBeanOut.toString());
iRemoteBookBinder.addBookOut(bookBeanOut);
Logger.i(RemoteBinderService.SERVICE_NAME + " addBookOut() after info:" + bookBeanOut.toString());
// addBookInOut
Logger.i("-------- addBookInOut() ------------------------");
int nextIntInOut = RandomUtils.randomInt(10000);
BookBean bookBeanInOut = new BookBean("书名-" + nextIntInOut, "作者-" + nextIntInOut,
(RandomUtils.randomInt(10000) + 10000) / 100d);
Logger.i(RemoteBinderService.SERVICE_NAME + " addBookInOut() before info:" + bookBeanInOut.toString());
iRemoteBookBinder.addBookInOut(bookBeanInOut);
Logger.i(RemoteBinderService.SERVICE_NAME + " addBookInOut() after info:" + bookBeanInOut.toString());
Logger.i("-------------------------------------------------");
然后在服务端进行数据修改,得到的日志为:
2021-01-19 10:46:08.613 29100-29100/com.example.service I/Logger: MainActivity$5.onClick(90): -------- addBookIn() ------------------------
2021-01-19 10:46:08.614 29100-29100/com.example.service I/Logger: MainActivity$5.onClick(94): zzf addBookIn() before info:BookBean{bookName='书名-8832', bookAuthor='作者-8832', bookPrice=140.58}
2021-01-19 10:46:08.617 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookIn(48): ------------------------服务端修改前的数据----------------------
2021-01-19 10:46:08.619 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookIn(49): BookBean{bookName='书名-8832', bookAuthor='作者-8832', bookPrice=140.58} ,Progress Name: com.renj.remote.binder ,Thread Name: Binder:29178_1
2021-01-19 10:46:08.619 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookIn(50): --------------------------------------------------------------
2021-01-19 10:46:08.619 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookIn(53): ------------------------服务端修改后的数据----------------------
2021-01-19 10:46:08.621 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookIn(54): BookBean{bookName='书名-8832', bookAuthor='zzf', bookPrice=140.58} ,Progress Name: com.renj.remote.binder ,Thread Name: Binder:29178_1
2021-01-19 10:46:08.621 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookIn(55): --------------------------------------------------------------
2021-01-19 10:46:08.622 29100-29100/com.example.service I/Logger: MainActivity$5.onClick(96): zzf addBookIn() after info:BookBean{bookName='书名-8832', bookAuthor='作者-8832', bookPrice=140.58}
2021-01-19 10:46:08.622 29100-29100/com.example.service I/Logger: MainActivity$5.onClick(99): -------- addBookOut() ------------------------
2021-01-19 10:46:08.623 29100-29100/com.example.service I/Logger: MainActivity$5.onClick(103): zzf addBookOut() before info:BookBean{bookName='书名-9785', bookAuthor='作者-9785', bookPrice=145.96}
2021-01-19 10:46:08.623 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookOut(60): ------------------------服务端修改前的数据----------------------
2021-01-19 10:46:08.624 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookOut(61): BookBean{bookName='null', bookAuthor='null', bookPrice=0.0} ,Progress Name: com.renj.remote.binder ,Thread Name: Binder:29178_1
2021-01-19 10:46:08.625 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookOut(62): --------------------------------------------------------------
2021-01-19 10:46:08.625 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookOut(65): ------------------------服务端修改后的数据----------------------
2021-01-19 10:46:08.626 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookOut(66): BookBean{bookName='null', bookAuthor='zzf', bookPrice=0.0} ,Progress Name: com.renj.remote.binder ,Thread Name: Binder:29178_1
2021-01-19 10:46:08.626 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookOut(67): --------------------------------------------------------------
2021-01-19 10:46:08.626 29100-29100/com.example.service I/Logger: MainActivity$5.onClick(105): zzf addBookOut() after info:BookBean{bookName='null', bookAuthor='zzf', bookPrice=0.0}
2021-01-19 10:46:08.626 29100-29100/com.example.service I/Logger: MainActivity$5.onClick(108): -------- addBookInOut() ------------------------
2021-01-19 10:46:08.627 29100-29100/com.example.service I/Logger: MainActivity$5.onClick(112): zzf addBookInOut() before info:BookBean{bookName='书名-8313', bookAuthor='作者-8313', bookPrice=105.42}
2021-01-19 10:46:08.627 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookInOut(72): ------------------------服务端修改前的数据----------------------
2021-01-19 10:46:08.628 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookInOut(73): BookBean{bookName='书名-8313', bookAuthor='作者-8313', bookPrice=105.42} ,Progress Name: com.renj.remote.binder ,Thread Name: Binder:29178_1
2021-01-19 10:46:08.628 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookInOut(74): --------------------------------------------------------------
2021-01-19 10:46:08.628 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookInOut(77): ------------------------服务端修改后的数据----------------------
2021-01-19 10:46:08.629 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookInOut(78): BookBean{bookName='书名-8313', bookAuthor='zzf', bookPrice=105.42} ,Progress Name: com.renj.remote.binder ,Thread Name: Binder:29178_1
2021-01-19 10:46:08.629 29178-29196/com.renj.remote.binder I/Logger: RemoteBinderService$RemoteBookBinderImpl.addBookInOut(79): --------------------------------------------------------------
2021-01-19 10:46:08.630 29100-29100/com.example.service I/Logger: MainActivity$5.onClick(114): zzf addBookInOut() after info:BookBean{bookName='书名-8313', bookAuthor='zzf', bookPrice=105.42}
2021-01-19 10:46:08.630 29100-29100/com.example.service I/Logger: MainActivity$5.onClick(116): -------------------------------------------------
从日志里可以看出,当参数用in 修饰时,我们修改服务端的数据,并不会影响客户端的值,而用out修饰时,服务端修改后,客户端也会修改,inout修饰时,服务端修改后,客户端也会修改。下面我们来看为什么会这样。
in
当我们客户端调用下面代码时:
iRemoteBookBinder.addBookIn(bookBeanIn);
@Override public void addBookIn(com.example.service.bean.BookBean bookBean) 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 ((bookBean!=null)) {
_data.writeInt(1);//1
bookBean.writeToParcel(_data, 0);//2
}
else {
_data.writeInt(0);
}
boolean _status = mRemote.transact(Stub.TRANSACTION_addBookIn, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().addBookIn(bookBean);
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
注释1的作用是用来在服务端判断用的。
注释2会调用
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(bookName);
dest.writeString(bookAuthor);
dest.writeDouble(bookPrice);
}
将bookBean写入到_data中,然后调用transact();
通过底层一系列的调用,最后会调用stub的onTranact(),具体分析在下面链接:
https://www.imooc.com/article/49742
case TRANSACTION_addBookIn:
{
data.enforceInterface(descriptor);
com.example.service.bean.BookBean _arg0;
if ((0!=data.readInt())) {
_arg0 = com.example.service.bean.BookBean.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
//然后在服务端调用Porxy的addBookIn(),这样最终会调用客户端的onTranact,
//将结果返回回去,在前面我就说过,Stub和Proxy在客户端和服务端同时都存在,而不是Proxy存在客户端,stub存在服务端。一般是从Proxy开始请求,Stub去接收处理请求。
this.addBookIn(_arg0);
reply.writeNoException();
return true;
}
先创建一个BookBean对象,调用createFromParcel():
public static final Creator<BookBean> CREATOR = new Creator<BookBean>() {
@Override
public BookBean createFromParcel(Parcel in) {
return new BookBean(in);
}
@Override
public BookBean[] newArray(int size) {
return new BookBean[size];
}
};
通过new的方式创建一个实例,然后将传过来的值赋值进去。
分析了整个流程,我们知道,调用期间传入的对象book只是将数据写入到Server,它的值进行并没有任何修改,就直接返回。所以in类型的参数,它向服务端传入数据,但是却不接受Server返回的值。
out
@Override public void addBookOut(com.example.service.bean.BookBean bookBean) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_addBookOut, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().addBookOut(bookBean);
return;
}
_reply.readException();
if ((0!=_reply.readInt())) {
bookBean.readFromParcel(_reply);//
}
}
finally {
_reply.recycle();
_data.recycle();
}
case TRANSACTION_addBookOut:
{
data.enforceInterface(descriptor);
com.example.service.bean.BookBean _arg0;
_arg0 = new com.example.service.bean.BookBean();//这里直接new一个空对象,没有把传过来的值赋值进去
this.addBookOut(_arg0);//调用这个方法将修改的字段写入_arg0
reply.writeNoException();
if ((_arg0!=null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);//将修改后的_arg0写入reply
}
else {
reply.writeInt(0);
}
return true;
}
整个方法调用期间传入的对象book并没有将数据写入到Server,它的值确实是Server返回的。
总结:out类型的参数,它并不向服务端传入数据,但是却接受Server返回的值。
inout
@Override public void addBookInOut(com.example.service.bean.BookBean bookBean) 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 ((bookBean!=null)) {
_data.writeInt(1);
bookBean.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
boolean _status = mRemote.transact(Stub.TRANSACTION_addBookInOut, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().addBookInOut(bookBean);
return;
}
_reply.readException();
if ((0!=_reply.readInt())) {
bookBean.readFromParcel(_reply);
}
}
finally {
_reply.recycle();
_data.recycle();
}
}
case TRANSACTION_addBookInOut:
{
data.enforceInterface(descriptor);
com.example.service.bean.BookBean _arg0;
if ((0!=data.readInt())) {
_arg0 = com.example.service.bean.BookBean.CREATOR.createFromParcel(data);//将接收到的数据赋值到_arg0
}
else {
_arg0 = null;
}
this.addBookInOut(_arg0);
reply.writeNoException();
if ((_arg0!=null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);//将修改后的_arg0写入reply
}
else {
reply.writeInt(0);
}
return true;
}
从上面可以看出,在inout中,是将接收到的data进行修改并返回。
总结:inout类型的参数,它既向服务端传入数据,也却接受Server返回的值。
最后用一张图去充分理解。
1611049703(1).png
网友评论