AIDL中的in,out,inout用法篇主要对跨进程传输对象三种定向tag方式的用法进行了讲解,验证了以下结论:
in:由cilent端流向server端,server端可以收到此对象的所有数据,收到之后会重新创建一个新的对象将数据填充进去,因为cilent端和server端是两个不同的对象,所以server端对数据的修改不会影响到client端的对象。
out:由server端流向client端,client端将对象传递给server端后,server端相当于收到的是一个空对象,没有client端此对象的任何数据,但是server端对此空对象的操作会影响到cilent端。
inout:对象可以双向流动,即server端能收到cilent发过来的对象的数据,server端对此对象的操作也能影响到cilent端
看此篇文章是根据上一篇的代码进行分析的
主要看一下系统给我们生成的IAIDLControl.java文件
/*
* This file is auto-generated. DO NOT MODIFY.
*/
package com.tct.aidlapplication;
public interface IAIDLControl extends android.os.IInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public void addStudent(com.tct.aidlapplication.Student student)
throws android.os.RemoteException;
public void addTeacher(com.tct.aidlapplication.Teacher teacher)
throws android.os.RemoteException;
public void addWorker(com.tct.aidlapplication.Worker worker)
throws android.os.RemoteException;
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.tct.aidlapplication.IAIDLControl {
private static final java.lang.String DESCRIPTOR = "com.tct.aidlapplication.IAIDLControl";
static final int TRANSACTION_addStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION +
0);
static final int TRANSACTION_addTeacher = (android.os.IBinder.FIRST_CALL_TRANSACTION +
1);
static final int TRANSACTION_addWorker = (android.os.IBinder.FIRST_CALL_TRANSACTION +
2);
/** Construct the stub at attach it to the interface. */
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.tct.aidlapplication.IAIDLControl interface,
* generating a proxy if needed.
*/
public static com.tct.aidlapplication.IAIDLControl asInterface(
android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) &&
(iin instanceof com.tct.aidlapplication.IAIDLControl))) {
return ((com.tct.aidlapplication.IAIDLControl) iin);
}
return new com.tct.aidlapplication.IAIDLControl.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 {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_addStudent: {
data.enforceInterface(descriptor);
com.tct.aidlapplication.Student _arg0;
if ((0 != data.readInt())) {
_arg0 = com.tct.aidlapplication.Student.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addStudent(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_addTeacher: {
data.enforceInterface(descriptor);
com.tct.aidlapplication.Teacher _arg0;
_arg0 = new com.tct.aidlapplication.Teacher();
this.addTeacher(_arg0);
reply.writeNoException();
if ((_arg0 != null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply,
android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_addWorker: {
data.enforceInterface(descriptor);
com.tct.aidlapplication.Worker _arg0;
if ((0 != data.readInt())) {
_arg0 = com.tct.aidlapplication.Worker.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addWorker(_arg0);
reply.writeNoException();
if ((_arg0 != null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply,
android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
default:return super.onTransact(code, data, reply, flags);
}
}
private static class Proxy implements com.tct.aidlapplication.IAIDLControl {
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 addStudent(com.tct.aidlapplication.Student student)
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 ((student != null)) {
_data.writeInt(1);
student.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addStudent, _data,
_reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void addTeacher(com.tct.aidlapplication.Teacher teacher)
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_addTeacher, _data,
_reply, 0);
_reply.readException();
if ((0 != _reply.readInt())) {
teacher.readFromParcel(_reply);
}
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void addWorker(com.tct.aidlapplication.Worker worker)
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 ((worker != null)) {
_data.writeInt(1);
worker.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addWorker, _data, _reply,
0);
_reply.readException();
if ((0 != _reply.readInt())) {
worker.readFromParcel(_reply);
}
} finally {
_reply.recycle();
_data.recycle();
}
}
}
}
}
AIDL中的in,out,inout用法篇定义了三个方法用来传输对象,Student定义为in,Teacher定义为out,Worker定义为inout,对应的三个方法是addStudent,addTeacher,addWorker。
首先来看Student的传输,定向tag为in
Proxy .addStudent
private static class Proxy implements com.tct.aidlapplication.IAIDLControl {
@Override
public void addStudent(com.tct.aidlapplication.Student student)
throws android.os.RemoteException {
//创建两个Parcel对象,_data用于将client端对象数据写入
//_reply传递给server端,tag为in用不到
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
//如果client端传过来的对象不为空
if ((student != null)) {
//写入int 1
_data.writeInt(1);
//将student的数据写入_data
student.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
//调用BinderProxy的transact进行binder传输,标识为TRANSACTION_addStudent
mRemote.transact(Stub.TRANSACTION_addStudent, _data,
_reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
student.writeToParcel
public class Student implements Parcelable {
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(this.age);
out.writeString(this.name);
}
}
我们看到调用student.writeToParcel方法就是将student的数据写入Parcel在内存中进行传输,mRemote.transact是进行binder传输,具体如何传输的非常复杂先不去深究,只要知道通过BinderProxy.transact传递标识就可以调到Binder.onTransact
mRemote.transact
public static abstract class Stub extends android.os.Binder implements com.tct.aidlapplication.IAIDLControl {
@Override
public boolean onTransact(int code, android.os.Parcel data,
android.os.Parcel reply, int flags)
throws android.os.RemoteException {
......
case TRANSACTION_addStudent: {
data.enforceInterface(descriptor);
com.tct.aidlapplication.Student _arg0;
//如果client传过来的student不为空
if ((0 != data.readInt())) {
//调用student的createFromParcel方法,并将client端包装好student数据的Parcel
//传递进去
_arg0 = com.tct.aidlapplication.Student.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
//调用server端具体实现
this.addStudent(_arg0);
reply.writeNoException();
return true;
}
}
student.createFromParcel
public class Student implements Parcelable {
public static final Creator<Student> CREATOR = new Creator<Student>() {
private Student(Parcel in) {
readFromParcel(in);
}
@Override
public Student createFromParcel(Parcel in) {
return new Student(in);
}
@Override
public Student[] newArray(int size) {
return new Student[size];
}
};
public void readFromParcel(Parcel in){
this.age = in.readInt();
this.name = in.readString();
}
}
createFromParcel方法重新创建了Student实例,构造方法中调用readFromParcel,readFromParcel中将client端包装好的数据反序列化出来并赋值给新创建的对象,接着调用server端addStudent方法将这个对象传进去,到这里我们就明白了,tag为in时,server端其实是重新创建的一个对象,并且将client端对象的数据一一赋值给新的对象,所以这两个对象互不影响
接着看Teacher传输,定向tag为out
private static class Proxy implements com.tct.aidlapplication.IAIDLControl {
@Override
public void addTeacher(com.tct.aidlapplication.Teacher teacher)
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_addTeacher, _data,
_reply, 0);
_reply.readException();
if ((0 != _reply.readInt())) {
teacher.readFromParcel(_reply);
}
} finally {
_reply.recycle();
_data.recycle();
}
}
}
和addStudent不同,addTeacher并没有调用writeToParcel方法将teacher数据写入Parcel
mRemote.transact
public static abstract class Stub extends android.os.Binder implements com.tct.aidlapplication.IAIDLControl {
......
@Override
public boolean onTransact(int code, android.os.Parcel data,
android.os.Parcel reply, int flags)
throws android.os.RemoteException {
case TRANSACTION_addTeacher: {
data.enforceInterface(descriptor);
com.tct.aidlapplication.Teacher _arg0;
//通过new直接创建了新的teacher对象
_arg0 = new com.tct.aidlapplication.Teacher();
//调用addTeacher方法传入此对象
this.addTeacher(_arg0);
reply.writeNoException();
if ((_arg0 != null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply,
android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
Teacher的无参构造里什么也没有做,关于此篇分析的代码全部在AIDL中的in,out,inout用法篇
所以tag为out时server端并不能收到client端对象的任何数据,调用server端addTeacher之后接着调用teacher的writeToParcel方法,使用的reply是client端传递过来Parcel,如果我们在server端addTeacher里对new出来的对象做了任何数据的修改则server端就会将数据写入reply传递给client端,Proxy.addTeacher中执行了mRemote.transact之后接着会执行teacher.readFromParcel(_reply);
teacher.readFromParcel
readFromParcel会读取server端给我们返回来的reply里的数据赋值给到client端的teacher
public class Teacher implements Parcelable {
.....
public void readFromParcel(Parcel in){
this.age = in.readInt();
this.name = in.readString();
}
}
到这里我们明白了tag为out时,server端并不能收到client端对象的任何数据,因为client根本就没有将数据写入Parcel传递给server端,而server端则是重新创建的一个实例,对此实例的修改都会返回给到client端并覆盖掉client端对象的值,所以out tag会影响client端对象。
接着看Worker传输,定向tag为inout
private static class Proxy implements com.tct.aidlapplication.IAIDLControl {
@Override
public void addWorker(com.tct.aidlapplication.Worker worker)
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 ((worker != null)) {
_data.writeInt(1);
//将client端对象数据写入Parcel
worker.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
//binder传输
mRemote.transact(Stub.TRANSACTION_addWorker, _data, _reply,
0);
_reply.readException();
if ((0 != _reply.readInt())) {
//将server端对数据的修改返回的replay读取到client端对象
worker.readFromParcel(_reply);
}
} finally {
_reply.recycle();
_data.recycle();
}
}
}
public static abstract class Stub extends android.os.Binder implements com.tct.aidlapplication.IAIDLControl {
......
@Override
public boolean onTransact(int code, android.os.Parcel data,
android.os.Parcel reply, int flags)
throws android.os.RemoteException {
case TRANSACTION_addWorker: {
data.enforceInterface(descriptor);
com.tct.aidlapplication.Worker _arg0;
if ((0 != data.readInt())) {
//调用createFromParcel创建新的对象,并将client端对象数据读取到新对象
_arg0 = com.tct.aidlapplication.Worker.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
//可以在此方法对对象数据进行修改
this.addWorker(_arg0);
reply.writeNoException();
if ((_arg0 != null)) {
reply.writeInt(1);
//将server端对象数据写入replay返回给client
_arg0.writeToParcel(reply,
android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
}
input其实就是结合了in,out的特点,server端可以获取到client端对象的数据,并且server端对对象的修改可以影响到client端,具体代码就不细分析了,和in,out都一样的
附上log:
D/dongjiao( 2501): before in student age = :20,name = :Tom
D/dongjiao( 2517): in student addStudent...age = :20,name = :Tom
D/dongjiao( 2501): before in student age = :20,name = :Tom
D/dongjiao( 2501): before out teacher age = :30,name = :Jerry
D/dongjiao( 2517): out teacher addTeacher age = :0,name = :null
D/dongjiao( 2501): end out teacher age = :35,name = :Jerry_update
D/dongjiao( 2501): before inout worker age = :40,name = :Tony
D/dongjiao( 2517): inout worker addWorker age = :40,name = :Tony
D/dongjiao( 2501): end inout worker age = :45,name = :tony_update
log分别表示传输前,传输到server,传输后,对象的值
全部源码在AIDL中的in,out,inout用法篇