IPC机制之了解AIDL(二)
IPC机制之了解AIDL(一)
主要讲解了AIDL的简单了解与使用
这节主要了解AIDL中的定向Tag
定向Tag
定向Tag主要分为三种 in out inout
官方介绍
定义服务接口时,请注意:
方法可带零个或多个参数,返回值或空值。
所有非原语参数均需要指示数据走向的方向标记。这类标记可以是 in、out 或 inout(见下方示例)。
原语默认为 in,不能是其他方向。
注意:您应将方向限定为真正需要的方向,因为编组参数的开销较大。
基本数据类型,String,CharSequence 默认是in (用out修饰会编译错误,short不能作为参数)
而其他的自定义类型则需要注明定向Tag。
区别:
AIDL中的定向 tag 表示了在跨进程通信中数据的流向,其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。
其中,数据流向是针对在客户端中的那个传入方法的对象而言的。in 为定向 tag 的话表现为服务端将会接收到一个那个对象的完整数据,但是客户端的那个对象不会因为服务端对传参的修改而发生变动;out 的话表现为服务端将会接收到那个对象的参数为空的对象,但是在服务端对接收到的空对象有任何修改之后客户端将会同步变动;inout 为定向 tag 的情况下,服务端将会接收到客户端传来对象的完整信息,并且客户端将会同步服务端对该对象的任何变动。
IPC机制之了解AIDL(一)中注释中//后续测试需要则此时可以用到
package com.example.aidl;
parcelable Student;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
String getName();
Student getStudent();
void setName( String name);
void setStudent(in Student stu);
void setOutName( out Student stu);
void setInOutName(inout Student stu);
void setDefaultName( String name);
}
void setStudent(in Student stu);
void setOutName( out Student stu);
void setInOutName(inout Student stu);
三个接口,分别为out,in ,inout。
开始测试:
@Override
public void setStudent(com.example.aidl.Student stu) throws RemoteException {
Log.e(TAG, "setStudent: 服务端收到参数属性"+stu.toString() );
this.student = stu;
stu.setName("service in change");
Log.e(TAG, "studentIn: " + stu.hashCode());
}
@Override
public void setOutName(com.example.aidl.Student stu) throws RemoteException {
Log.e(TAG, "setStudent: 服务端收到参数属性"+stu.toString() );
student = stu;
stu.setName("service out change");
Log.e(TAG, "studentOut: " + stu.hashCode());
}
@Override
public void setInOutName(com.example.aidl.Student stu) throws RemoteException {
Log.e(TAG, "setStudent: 服务端收到参数属性"+stu.toString() );
student = stu;
stu.setName("service InOut change");
Log.e(TAG, "studentInOut: " + stu.hashCode());
}
可以看到服务端每一个方法实现时都对参数stu的name属性进行了更改。
客户端:
aidl_change.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (studentIn != null) {
client_ok_in.setText(studentIn.toString());
Log.e(TAG, "onClick: studentIn.hashCode():"+studentIn.hashCode() );
} else {
client_ok_in.setText("null");
}
if (studentInOut != null) {
client_ok_inout.setText(studentInOut.toString());
Log.e(TAG, "onClick: studentInOut.hashCode():"+studentInOut.hashCode() );
} else {
client_ok_inout.setText("null");
}
if (studentOut != null) {
client_ok_out.setText(studentOut.toString());
Log.e(TAG, "onClick: studentOut.hashCode():"+studentOut.hashCode() );
} else {
client_ok_out.setText("null");
}
}
});
aidl_change1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
studentOut = new Student("client out Student", 1);
Log.e(TAG, "onClick:before studentOut.hashCode()=="+studentOut.hashCode() );
interfaceA.setOutName(studentOut);
Log.e(TAG, "onClick:after studentOut.hashCode()=="+studentOut.hashCode() );
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
aidl_change2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
studentInOut = new Student("client inout Student", 2);
Log.e(TAG, "onClick:before studentInOut.hashCode()=="+studentInOut.hashCode() );
interfaceA.setInOutName(studentInOut);
Log.e(TAG, "onClick:after studentInOut.hashCode()=="+studentInOut.hashCode() );
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
aidl_change3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
studentIn = new Student("client in Student", 3);
Log.e(TAG, "onClick:before studentIn.hashCode()=="+studentIn.hashCode() );
interfaceA.setStudent(studentIn);
Log.e(TAG, "onClick:after studentIn.hashCode()=="+studentIn.hashCode() );
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
客户端分别对不同的方法,设置了不同的参数,后续统一显示,可以进行对比。
初始化:
3个对象分别为null,点击后创建对象。
依次点击设置不同的属性
in:
可以看出in时,服务端已经设置成功,但是服务端的设置name属性只对service端的student起效,客户端中的student并没有属性变化。
并且从日志中可以看出,服务端收到了客户端对象的所有属性,但是服务端与客户端的student并不是一个对象,并且在服务端在运行方法后,客户端对象的hashcode仍然是一个。
out
在此点击后,刷新服务端和客户端数据,服务端设置的属性name=“client out Student”, old=1,由于服务端我们统一改变了name属性,
现在我们可以看出,服务端中,name已经更改(服务端自己改的,肯定成功),而old变成了0,服务端接收的对象name=null,old=0.也就是说,客户端的数据并没有传输到服务端。而这时服务端更改了name属性,客户端竟然同步了服务端的属性,name变成了service out change 。
不仅如此,可以看出客户端与服务端的hashcode不相同,并且客户端的对象虽然属性进行了变化,但是hashcode可以看出仍然是原来的对象,改变的只有属性,对象地址本身并没有变化。
inout
再进行inout测试,从图中可以看出,客户端的old属性已经传入了服务端,并且本身仍然是2,因为服务器没有对old属性更改,而name变为服务端更改的属性。这时可以看出,客户端的属性不仅传入了服务端,而且服务端对对象的更改会对客户端有影响。
再看上面的图,明显看出客户端与服务端的对象不是一个对象,但是属性却会跟随服务端的改变而变化。
结论
in out inout 传输的对象,客户端并没有将对象传输至服务端,并且对象本身地址并不会改变。
定向Tag | 属性 |
---|---|
in | 客户端可以将对象属性传输到服务端,服务端对属性更改后,客户端属性并不会发生变化。 |
out | 客户端不可以将对象属性传输到服务端,服务端对属性更改后,客户端属性会发生变化。 |
inout | 客户端可以将对象属性传输到服务端,服务端对属性更改后,客户端属性会发生变化。 |
深入了解可以看下aidl自动生成的类
其中的代理class Proxy以及onTransact方法,可以有更深一点的了解。
aidl小例子