一、什么是AIDL?
- AIDL是一个缩写,全称是Android Interface Definition Language,也就是Android接口定义语言;
- AIDL是进行进程间通信的常用方式
二、怎么使用AIDL?
-
总体来说,使用AIDL的过程可以总结为:
-
- 定义AIDL接口
- 服务端对AIDL接口进行逻辑补全
- 客户端通过AIDL接口调用服务端逻辑进行各种操作
数据跨进程传输过程就在这种调用与被调用过程中通过binder进行
代码详析(非原始数据类型):
1. 待传输对象类:
public class People implements Parcelable {
private String name;
private int age;
private String sex;
//无参构造函数
public People() {
name = "";
age = 0;
sex = "";
}
//一般构造函数,提供给用户构造People对象
public People(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
//Android studio可自动生成,提供给系统 Creator 生成People对象
protected People(Parcel in) {
name = in.readString();
age = in.readInt();
sex = in.readString();
}
//这个对象是AIDL中tag为in或inout时候调用的,即从序列化流中创建people对象的时候调用
public static final Creator<People> CREATOR = new Creator<People>() {
@Override
public People createFromParcel(Parcel in) {
return new People(in);
}
@Override
public People[] newArray(int size) {
return new People[size];
}
};
//Parcel的内容包含文件描述符,一般传0
@Override
public int describeContents() {
return 0;
}
//如果你需要使用out或inout的tag的话,就要自己定义这个函数,它目的是通过流修改当前people对象的属性
public void readFromParcel(Parcel parcel) {
name = parcel.readString();
age = parcel.readInt();
sex = parcel.readString();
}
//将为tag为in的数据写入流中传输
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(name);
parcel.writeInt(age);
parcel.writeString(sex);
}
//无特殊意义,只是为了方便显示
@Override
public String toString() {
return name + ", " + age + " years old, is a " + sex;
}
2. 待传输对象的AIDL文件(AIDL类1):
package com.AIDL_demo;
parcelable People;//只需要声明本类为parcelable
3. 定义接口方法的AIDL(AIDL类2):
package com.AIDL_demo;
import com.AIDL_demo.People;
interface IMethod {
List<People> getPeople();
}
4. 服务端:
public class MyService extends Service {
List<People> people = new ArrayList<>();
private final IMethod.Stub method = new IMethod.Stub() {
@Override
public List<People> getPeople() throws RemoteException {
return people;
}
};
public MyService() {
People man1 = new People("Mike", 18, "male");
people.add(man1);
People man2 = new People("Lucy", 26, "female");
people.add(man2);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return method;
}
}
5. 客户端关键代码:
//跨进程启动service
public void bindRemoteService() {
Intent intent = new Intent();
intent.setAction("my_remote_service");//manifest中service的action
intent.setPackage("com.AIDL_demo");//服务端的package名
bindService(intent, connection, Service.BIND_AUTO_CREATE);
}
private IMethod method;
private final ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
method = IMethod.Stub.asInterface(iBinder);//获取远程服务端的AIDL通信对象
if (method == null) {
Log.d("LogTag", "IMethod is null");
return;
}
try {
List<com.AIDL_demo.People> peopleList = method.getPeople();//调用远程接口获取服务端数据
//打印数据
StringBuilder stringBuilder = new StringBuilder();
for (People people : peopleList) {
stringBuilder.append(people.toString());
stringBuilder.append("\n");
}
Log.d("LogTag", stringBuilder.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.d("LogTag", "service disconnected");
}
};
-
最终运行会在客户端Logcat中打印:
-
D/LogTag: Mike, 18 years old, is a male
Lucy, 26 years old, is a female
结论:成功跨进程通信,将服务端创建的两个People对象,传输到了客户端;
注意事项
- AIDL文件必须和这个非原始数据类在同名包下,只是一个在Java目录下,一个在AIDL目录下:
- AIDL中在参数为非默认数据类型的变量时,都需要设置定向的tag
ADIL中默认支持Java八大基本类型和String,CharSequence,List(元素必须是AIDL支持的,List可以使用泛型),Map(元素必须是AIDL支持,Map不支持泛型);
AIDL文件可以分为两类。一类是用来定义非默认支持的数据类型,以供其他AIDL文件使用的,如上面代码中的 “AIDL类1” ;一类是用来定义方法接口,用来完成跨进程通信的,如上面代码中的 “AIDL类2” 。