AIDL实例

说到进程间通信,一般首先就会想到AIDL,也看了很多文章,做下笔记,记录一下,方便以后查阅。

对于 AIDL 我是这样理解的,首先进程间是无法通信的,那要通信就得有一个媒介或者说两个进程有统一对外的接口可以相互识别,从这个 AIDL全程的名字Android Interface Definition Language (android 接口定义语言) 来看不难看出它就是我们进程间通信的媒介,它可以实现我们想要的通信。

在翻阅网上各类文章的讲解后,我认为一个比较好的实例可以更好理解这个东西,具体如下:

第一步

我们新创建两个module,代表我们两个进程,进程名称默认就是我们程序的包名:
image.png

第二步

我们先编写service这个module里的代码,先定义一个 Person的一个bean对象,记住一定要implements Parcelable 接口,大致如下:
image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class Person implements Parcelable {
private String mName;

public Person(String name) {
mName = name;
}

protected Person(Parcel in) {
mName = in.readString();
}

public static final Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}

@Override
public Person[] newArray(int size) {
return new Person[size];
}
};

@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mName);
}

@Override
public String toString() {
return "\nPerson{" +
"mName='" + mName + '\'' +
'}';
}

}

然后我们再新建一个文件夹:aidl,新建一个包名和Person类一模一样的包名和与之对应的aidl,还有一个我们对外提供获取person集合的一个aidl:
image.png
Person.aidl里,我们序列化我们java里的 Person 类:

1
2
3
4
5
package com.example.service.bean;

//还要和声明的实体类在一个包里,同时注意不要新建aidl文件,因为你会发现,新建不了,
//提示你名称唯一,此时你新建一个file,名字为Person.aidl就可以,需要特别注意下
parcelable Person;

IMyAidl.aidl 文件提供对外方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// IMyAidl.aidl
package com.example.service.bean;
//特别注意一定要手动导包,不会自动导包
import com.example.service.bean.Person;

// Declare any non-default types here with import statements
//可以理解为通信媒介
interface IMyAidl {

/**
* 除了基本数据类型,其他类型的参数都需要标上方向类型:in(输入), out(输出), inout(输入输出)
*/
void addPerson(in Person person);

List<Person> getPersonList();
}

然后在我们的java文件里,新建一个MyAidlService,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class MyAidlService extends Service {

private final String TAG = this.getClass().getSimpleName();

private ArrayList<Person> mPersons;

/**
* 创建生成本地的binder ,实现AIDL的方法
*/
private IBinder mIBinder = new IMyAidl.Stub(){

@Override
public void addPerson(Person person) throws RemoteException {
mPersons.add(person);
}

@Override
public List<Person> getPersonList() throws RemoteException {
return mPersons;
}
};

/**
* 客户端与服务端绑定时的回调,返回IBinder对象后客户端就可以通过它远程调用服务端的方法,即实现了通讯

* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
mPersons = new ArrayList<>();
return mIBinder;
}

@Override
public void onCreate() {
super.onCreate();
}

最后别忘了在清单文件中注册MyAidlService

1
2
3
4
<service
android:name="com.example.service.MyAidlService"
android:enabled="true"
android:exported="true" />

到此,我们完成了service端的工作:

第三步

将我们刚才创建好的aidl文件夹拷贝到 app modulemain文件夹下,在MainActivity中绑定服务,

1
2
3
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.service","com.example.service.MyAidlService"));
bindService(intent,mConnection,BIND_AUTO_CREATE);

其中这个mConnection可以让我们拿到IMyAidl对象的代理

1
2
3
4
5
6
7
8
9
10
11
12
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

mAidl = IMyAidl.Stub.asInterface(iBinder);
}

@Override
public void onServiceDisconnected(ComponentName componentName) {
mAidl = null;
}
};

通过返回的IBinder 拿到这个IMyAidl,此时我们就可以通信了,例如我们调用IMyAidl中的addPerson方法,再调用getPersonList看看:

1
2
3
4
5
6
7
8
9
10
11
Random random = new Random();
Person person = new Person("qian"+random.nextInt(20));

try{
mAidl.addPerson(person);
List<Person> mPersons = mAidl.getPersonList();

tvName.setText(mPersons.toString());
}catch (Exception e){
e.printStackTrace();
}

打印发现list 返回了我们添加的Person,完成了appservice两个进程间的通信。
demo地址:https://github.com/QQabby/AIDLDemo

-------------本文结束感谢您的阅读-------------