Android跨进程通信-AIDL(使用)

本篇将介绍进程间通信(IPC)机制-AIDL

Android跨进程通信-AIDL(使用)

本文将介绍进程间通信(IPC)机制-AIDL

AIDL介绍

ADIL是Android中进程间通信的一种机制,我们可以利用它定义客户端与服务端进行进程间通信的编程接口

在Android中,一个进程是无法访问另一个进程的内存,所以为了解决进程间通讯的问题,Android使用一种接口定义语言来公开服务的接口,本质上,AIDL非常像一个接口,通过公开接口,让别的进程调用该接口,从而实现进程间的通讯。

使用AIDL

数据实体类

首先先创建一个实体数据类,用来进程间进行通信

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
class Person(
val name: String?,
val age: Int
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readInt()
) {
}

override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name)
parcel.writeInt(age)
}

override fun describeContents(): Int {
return 0
}

companion object CREATOR : Parcelable.Creator<Person> {
override fun createFromParcel(parcel: Parcel): Person {
return Person(parcel)
}

override fun newArray(size: Int): Array<Person?> {
return arrayOfNulls(size)
}
}
}

注意!这里的Person的目录结构必须要和下方创建的aidl文件目录结构一致

什么意思呢,就是说这里创建的Person类是直接放在java下的,那么等下创建的aidl文件也必须是在最外层

这个类还需要实现Parcelable接口,为什么呢,因为AIDL只支持几种数据类型

  1. java基本类型
  2. List、Map
  3. 实现了Parcelable接口

所以说这里需要继承Parcelable

AIDL接口

在Android Studio高版本中,通过右键创建的.aidl文件都会被Android Studio强制放到main下的aidl文件夹中

这里的aidl文件是放在最外层的,那么刚刚创建的Person文件也是需要放在java下的最外层

image-20210826194036950

我们还需要在aidl文件夹下在创建一个文件夹,名字为包名即可

之后,首先先创建一个名字为Person.aidl类,是的,这里的名字与上面创建的数据实体类的名称相同

这里的 Person 我理解的是 Person.aidl,然后通过 Person.aidl 又找到真正的实体 Person 类。

1
2
3
4
// Person.aidl
package com.example.studynode;

parcelable Person;

这里使用了自定义Parcelable对象,接着我们去定义个接口用来通信

1
2
3
4
5
6
7
8
9
10
11
12
// IMyAidl.aidl
package com.example.studynode;

import com.example.studynode.Person;

interface IMyAidl {

void addPerson(in Person person);

List<Person> getPersonList();

}

上述代码中,我们定义了两个方法,一个是用来添加数据,一个是用来获取总共的数据。之后就只需点一下有右上角的小锤子(Make Project)就ok了,系统会自动的生成一个java文件

服务端

这里就使用Service来进行跨进程通信,所以就先创建一个Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class AidlService : Service() {

private var mPersons: ArrayList<Person>? = null

private val mInBinder: IBinder = object : IMyAidl.Stub() {
override fun addPerson(person: Person) {
mPersons?.add(person)
}

override fun getPersonList(): MutableList<Person>? {
return mPersons
}

}

override fun onBind(intent: Intent?): IBinder {
mPersons = ArrayList()
return mInBinder
}
}

上面代码总共创建了两个东西

  1. 创建了一个ArrayList,用来存放数据
  2. 为了实现来自.aidl文件生成的接口,需要继承Binder接口(例如Ibinder接口),并且实现从.aidl文件中继承法,在上面代码中,使用匿名实例实现一个叫IMyAidl(定义在IMyAidl.aidl中)的接口,实现了两个方法,addPerson和getPersonList

客户端

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
42
43
44
45
46
47
48
class AidlActivity : BaseSimpleActivity<ActivityAidlBinding>() {

override val binding: ActivityAidlBinding by lazy { ActivityAidlBinding.inflate(layoutInflater) }

private var iMyAidl: IMyAidl? = null

private val adapter: AidlAdapter by lazy { AidlAdapter() }

private val serviceConnection: ServiceConnection = object : ServiceConnection {

override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Log.d("AIDL", "onServiceConnected: 绑定Service成功")
iMyAidl = IMyAidl.Stub.asInterface(service)
}

override fun onServiceDisconnected(name: ComponentName?) {
iMyAidl = null
}

}

override fun initView(savedInstanceState: Bundle?) {
binding.aidlList.apply {
layoutManager =
LinearLayoutManager(this@AidlActivity)
adapter = this@AidlActivity.adapter
}
binding.aidlButton1.setOnClickListener {
iMyAidl?.addPerson(Person("Tom", Random.nextInt(10)))
}
binding.aidlButton2.setOnClickListener {
iMyAidl?.personList?.let {
adapter.setList(it)
}
}
}

override fun initData() {
val intent = Intent().apply {
component = ComponentName(
"com.example.studynode",
"com.example.studynode.aidl.service.AidlService"
)
}
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
}

}

上述代码中,主要就是绑定了Service,至于IMyAidl这个类就是系统为我们刚刚写的aidl接口自动创建的类。然后我们在绑定服务中拿到了Binder并转换成了AIDL,最后通过按钮来进行通信,按下按钮就向Servlce多添加组数据,然后使用Recycler展示出来

ComponentName:这个类主要用来定义可见一个应用程序组件,例如:Activity,Service,BroadcastReceiver或者ContentProvider。也就是说可以使用ComponentName来启动四大组件