学更好的别人,
做更好的自己。
——《微卡智享》
本文长度为2478字,预计阅读6分钟
前言
Android的AIDL使用和异常报错都已经介绍过了,今天这篇还是在原来的Demo基础上加入几个AIDL的进阶使用方法。
】
AIDL进阶使用
微卡智享
in,out,inout的使用
关于in,out,inout在AIDL的基础介绍中有提到过
AIDL中还有定向的Tag,包括了in、out、inout。其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。
Vaccae,公众号:微卡智享Android Aidl跨进程通讯的简单使用
根据字面意思可以很简单的理解,所以我们直接做一个函数实现inout的方法即可。
-
在服务端的Aidl文件中加入一个新的函数updateTestDatsList,输入的参数设置为inout
-
Build后在Service的object : ITestDataAidlInterface.Stub()里面写入实现,这里我们先将传入的list里面再自定义加入一条,然后插入到Service缓存的List列表中,再将传入的listdata清空后,把Service缓存中的所有数据都插入传入的listdata
-
因为是跨进程,所以客户端需要将修改后的Aidl复制过来替换原来的,然后在MainActivity中写入实现调用
运行效果
点击更新列表后的对比,可以看到,使用inout参数,传入的list最后也已经修改完成。
AIDL使用Bundle传递多个数据
AIDL可以使用Bundle类封装通讯数据,用于传递一些复杂的对象或者多个对象。
Bundle类是一个键值对的容器,它可以存储不同类型的数据,并且实现了Parcelable接口,所以可以在进程间传输。
-
Service的AIDL接口加入新的函数transBundle,传入的参数就是Bundle
-
在Service加入接口实现,这里我们测试里面加入一个Float,一个Int,和一个List数据,将原来的价格和数量都统一改为一样的数据后,再将传入的list加入到后面,最后展现出来,
划重点
Android有两种不同的classloaders:framework classloader和apk classloader,其中framework classloader知道怎么加载android classes,apk classloader继承自framework classloader,所以也知道怎么加载android classes。但在应用刚启动时,默认class loader是apk classloader,在系统内存不足应用被系统回收会再次启动,这个默认class loader会变为framework classloader了,所以对于自己的类会报ClassNotFoundException,就会出现android.os.BadParcelableException: ClassNotFoundException when unmarshalling
所以在bundle数据读取前,先设置classloader后,才能正确地读取自定义类
it.classLoader = TestData::class.java.classLoader
override fun transBundle(bundle: Bundle?): MutableList<TestData> {
bundle?.let { it ->
/*
Android有两种不同的classloaders:framework classloader和apk classloader,
其中framework classloader知道怎么加载android classes,
apk classloader继承自framework classloader,所以也知道怎么加载android classes。
但在应用刚启动时,默认class loader是apk classloader,在系统内存不足应用被系统回收会再次启动,
这个默认class loader会变为framework classloader了,所以对于自己的类会报ClassNotFoundException
就会出现android.os.BadParcelableException: ClassNotFoundException when unmarshalling
*/
//所以在bundle数据读取前,先设置classloader后,才能正确的读取自定义类
it.classLoader = TestData::class.java.classLoader
val price = it.getFloat("price")
val qty = it.getInt("qty")
mTestDatas.map { t->
t.price = price
t.qty = qty
}
val list = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
it.getParcelableArrayList("listdatas", TestData::class.java)
} else {
it.getParcelableArrayList<TestData>("listdatas")
}
list?.let { item->
mTestDatas.addAll(item)
}
}
return mTestDatas
}
-
客户端中一样要把AIDL复制过来后,写实现方法
运行效果
关于oneway关键字
AIDL中的oneway关键字,主要用来使IPC调用变成非阻塞的。
oneway需要注意的几点:
-
将远程调用改为异步调用,使得远程调用变成非阻塞式的,客户端不需要等待服务端的处理,只是发送数据并立即返回。要注意的是,oneway修饰本地调用没有效果,仍然是同步的,客户端需要等待服务端的处理。
-
在同一个IBinder对象调用中,会按照调用顺序依次执行,不同的IBinder对象可能导致调用顺序和执行顺序不一致。
-
oneway不能带有返回值或抛出异常,因为客户端是无法接收的。
Demo源码中也已经更新上传了。
源码地址
https://github.com/Vaccae/AndroidAIDLDemo.git
点击原文链接可以看到“码云”的源码地址
完
往期精彩回顾
Android Aidl跨进程通讯(二)--异常捕获处理
Android Aidl跨进程通讯的简单使用
Android BlueToothBLE入门(三)——数据的分包发送和接收(源码已更新)