本篇将介绍进程间通信(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只支持几种数据类型
- java基本类型
- List、Map
- 实现了Parcelable接口
所以说这里需要继承Parcelable
AIDL接口
在Android Studio高版本中,通过右键创建的.aidl文件都会被Android Studio强制放到main下的aidl文件夹中
这里的aidl文件是放在最外层的,那么刚刚创建的Person文件也是需要放在java下的最外层
我们还需要在aidl文件夹下在创建一个文件夹,名字为包名即可
之后,首先先创建一个名字为Person.aidl类,是的,这里的名字与上面创建的数据实体类的名称相同
这里的 Person 我理解的是 Person.aidl,然后通过 Person.aidl 又找到真正的实体 Person 类。
1 2 3 4
| package com.example.studynode;
parcelable Person;
|
这里使用了自定义Parcelable对象,接着我们去定义个接口用来通信
1 2 3 4 5 6 7 8 9 10 11 12
| 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 } }
|
上面代码总共创建了两个东西
- 创建了一个ArrayList,用来存放数据
- 为了实现来自.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来启动四大组件