Android两个进程间内存相互独立不能互相访问,跨进程传输非默认类型对象需要先序列化,而不能直接简单传递引用,序列化的目的是将对象数据以能够在内存中流通的形式从一个进程传递到另一个进程,两个进程对象的传递类似深度clone,client端将对象数据写入Parcel(writeToParcel),server端从Parcel(readFromParcel)读取对象数据并重新创建一个同样的对象将读取到的数据填充到此对象,但这两个对象并不是一样的,只是他们的数据完全一样。
in,out,inout
两个进程中要传递的对象必须实现Parcelable接口,AIDL中序列化的对象传递还必须指定定向tag,tag表示数据的流通方向。
in:由cilent端流向server端,server端可以收到此对象的所有数据,收到之后会重新创建一个新的对象将数据填充进去,因为cilent端和server端是两个不同的对象,所以server端对数据的修改不会影响到client端的对象。
out:由server端流向client端,client端将对象传递给server端后,server端相当于收到的是一个空对象,没有client端此对象的任何数据,但是server端对此空对象的操作会影响到cilent端。
inout:对象可以双向流动,即server端能收到cilent发过来的对象的数据,server端对此对象的操作也能影响到cilent端
接下来用代码演示下三种tag的用法
定义三个传输对象的AIDL文件,Student.aidl,Teacher.aidl,Worker.aidl,三个对应java文件Student.java,Teacher.java,Worker.java并实现Parcelable序列化接口,跨进程传输的对象的定义规则就是一个java类对应一个aidl文件,这个三个对象文件分别用来演示in,out,inout三种tag
Student.aidl
package com.tct.aidlapplication;
parcelable Student;
Teacher.aidl
package com.tct.aidlapplication;
parcelable Teacher;
Worker.aidl
package com.tct.aidlapplication;
parcelable Worker;
Student .java
package com.tct.aidlapplication;
import android.os.Parcel;
import android.os.Parcelable;
public class Student implements Parcelable {
public int age;
public String name;
public Student(){}
public Student(int age,String name){
this.age = age;
this.name = name;
}
private Student(Parcel in) {
readFromParcel(in);
}
//server端收到client端的数据后用Creator来构造server端的一个新对象
public static final Creator<Student> CREATOR = new Creator<Student>() {
@Override
public Student createFromParcel(Parcel in) {
return new Student(in);
}
@Override
public Student[] newArray(int size) {
return new Student[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(this.age);
out.writeString(this.name);
}
public void readFromParcel(Parcel in){
this.age = in.readInt();
this.name = in.readString();
}
}
Teacher .java
package com.tct.aidlapplication;
import android.os.Parcel;
import android.os.Parcelable;
public class Teacher implements Parcelable {
public int age;
public String name;
public Teacher(){}
public Teacher(int age,String name){
this.age = age;
this.name = name;
}
private Teacher(Parcel in) {
readFromParcel(in);
}
//server端收到client端的数据后用Creator来构造server端的一个新对象
public static final Creator<Teacher> CREATOR = new Creator<Teacher>() {
@Override
public Teacher createFromParcel(Parcel in) {
return new Teacher(in);
}
@Override
public Teacher[] newArray(int size) {
return new Teacher[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(this.age);
out.writeString(this.name);
}
public void readFromParcel(Parcel in){
this.age = in.readInt();
this.name = in.readString();
}
}
Worker .java
package com.tct.aidlapplication;
import android.os.Parcel;
import android.os.Parcelable;
public class Worker implements Parcelable {
public int age;
public String name;
public Worker(){}
public Worker(int age, String name){
this.age = age;
this.name = name;
}
private Worker(Parcel in) {
readFromParcel(in);
}
//server端收到client端的数据后用Creator来构造server端的一个新对象
public static final Creator<Worker> CREATOR = new Creator<Worker>() {
@Override
public Worker createFromParcel(Parcel in) {
return new Worker(in);
}
@Override
public Worker[] newArray(int size) {
return new Worker[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(this.age);
out.writeString(this.name);
}
public void readFromParcel(Parcel in){
this.age = in.readInt();
this.name = in.readString();
}
}
可以看到这序列化对象都是同样的格式
接着定义再一个AIDL文件IAIDLControl.aidl,申明server端方法,由client端调用将对象传递过去
要注意传递的对象Student,Teacher ,Worker 在同一个包中也需要引入
IAIDLControl.aidl
// IAIDLControl.aidl
package com.tct.aidlapplication;
// Declare any non-default types here with import statements
import com.tct.aidlapplication.Student;
import com.tct.aidlapplication.Teacher;
import com.tct.aidlapplication.Worker;
interface IAIDLControl {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void addStudent(in Student student);
void addTeacher(out Teacher teacher);
void addWorker(inout Worker worker);
}
创建完成之后点击Android Studio的make project或者clean或者快捷键Ctrl+F9重新编译一下项目就会自动生成一系列代码如下:我是进行了格式化的,系统生成的可读性很差
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();
}
}
}
}
}
IAIDLControl.java的代码我们等下回过头来看,接着创建AIDLService对IAIDLControl的方法具体实现,三个方法实现都一样,打印一句log并且修改传递过来对象的属性值
注意AIDLService在Androidmanifests文件中文件中需要配置android:process=“com.aidl”,要和client端Activity处于不同进程
AIDLService.java
package com.tct.aidlapplication;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import androidx.annotation.Nullable;
public class AIDLService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return stub;
}
private IAIDLControl.Stub stub = new IAIDLControl.Stub() {
@Override
public void addStudent(Student student) throws RemoteException {
Log.d("dongjiao","in student addStudent...age = :"+student.age+",name = :"+student.name);
student.age = 35;
student.name = "Tom_update";
}
@Override
public void addTeacher(Teacher teacher) throws RemoteException {
Log.d("dongjiao","out teacher addTeacher age = :"+teacher.age+",name = :"+teacher.name);
teacher.age = 35;
teacher.name = "Jerry_update";
}
@Override
public void addWorker(Worker worker) throws RemoteException {
Log.d("dongjiao","inout worker addWorker age = :"+worker.age+",name = :"+worker.name);
worker.age = 45;
worker.name = "tony_update";
}
};
}
接着创建MainActivity用于调用这三个方法,activity_main放了三个Button分别调用AIDLService的三个方法,分别创建Student,Teacher,Worker对象传递给AIDLService
MainActivity.java
package com.tct.aidlapplication;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
public Button button1;
public Button button2;
public Button button3;
public IAIDLControl mIAIDLControl;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIAIDLControl = IAIDLControl.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1 = findViewById(R.id.button1);
button2 = findViewById(R.id.button2);
button3 = findViewById(R.id.button3);
Intent intent = new Intent(this,AIDLService.class);
this.bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);
final Student student = new Student(20,"Tom");
final Teacher teacher = new Teacher(30,"Jerry");
final Worker worker = new Worker(40,"Tony");
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Log.d("dongjiao","before in student age = :"+student.age+",name = :"+student.name);
mIAIDLControl.addStudent(student);
Log.d("dongjiao","before in student age = :"+student.age+",name = :"+student.name);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Log.d("dongjiao","before out teacher age = :"+teacher.age+",name = :"+teacher.name);
mIAIDLControl.addTeacher(teacher);
Log.d("dongjiao","end out teacher age = :"+teacher.age+",name = :"+teacher.name);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
button3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Log.d("dongjiao","before inout worker age = :"+worker.age+",name = :"+worker.name);
mIAIDLControl.addWorker(worker);
Log.d("dongjiao","end inout worker age = :"+worker.age+",name = :"+worker.name);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
}
这三个方法都是在Activity调用addXXXX前后以及AIDLService此方法中打印log并修改传递过来的对象的属性,验证三种tag方式client端传递到server端的对象数据是否为空以及AIDLService修改数据之后是否对client端对象由影响
log验证
我们来看三个Button依次点击一次打印的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
可以看到定义tag为in时server端收到了cilent端的数据,并且在server端对数据的修改不能影响到client端对象,定向tag为out时server端收到的是一个空对象,并且server端对数据的修改能够影响到client端,定向tag为inout时server端既能收到client端的对象数据,并且对数据的修改也能影响到client端
到此AIDL三种tag的用法就已经讲解完了,后一篇文章会对三种tag原理进行讲解