事先声明,本文所有说法均是临时起意,没有完整代码给予参考
AIDL(Android Interface Definition Language)是一种用于定义和实现跨进程通信接口的语言。它是 Android 系统中用于进程间通信(IPC)的一种机制,允许一个进程向另一个进程发送请求并获取响应。
从介绍中可与看到,AIDL是被用作跨进程传输数据的一种方式。
有很多人说我开发安卓几年就没用个AIDL,其实也正常,大多APP只有一个进程,用不上这玩意。一个APP里多个进程的操作多数用来做些花里胡哨的操作,比如进程守护、加大内存。但是这里叔劝你一句,没必要,叔怕你把握不住。
回归本质,就让AIDL做它该做的事情,跨进程通信,跨APP通信
Socket
startActivity
、startService
、BroadcastReceiver
、ContentProvider
Socket
和文件共享
相比,实现简单。(虽然在很久很久以前,AIDL是手动实现的)Service
,在onBind
里返回个binder
对象bindService
,通过ServiceConnection
回调来获取aidl
对象这么用行不行,行
,大家都这么用绝对是可以的。
但是方便吗?一点也不方便。 我这里说一句,只能异步的操作都不方便,代码丑,谁赞成谁反对。 谁反对站出来 。
所以题外话, DataStore
NO ,协程
YES。
好了,多余的题外话说完了,diss完别人,到你这又该怎么用。
ContentProvider
的结果是同步返回的,可以先这样,再那样:
1.自定义BinderCursor
继承MatrixCursor
import android.database.MatrixCursor;
import android.os.Bundle;
import android.os.IBinder;
public class BinderCursor extends MatrixCursor {
private static final String KEY_BINDER = "binder";
private final Bundle mBinderExtra = new Bundle();
public BinderCursor(IBinder binder) {
super(new String[]{"service"});
if (binder != null) {
mBinderExtra.putBinder(KEY_BINDER, binder);
}
}
@Override
public Bundle getExtras() {
return mBinderExtra;
}
}
2.自定义AidlCoreProvider
继承ContentProvider
class MdmCoreProvider : ContentProvider() {
override fun onCreate(): Boolean {
return true
}
override fun query(uri: Uri, projection: Array<String>?, selection: String?, selectionArgs: Array<String>?, sortOrder: String?): Cursor? {
//这里可以根据条件判断返回具体某个Aidl实现类
val binder = Aidl实现类对象()
return BinderCursor(binder)
}
override fun getType(uri: Uri): String? {
return null
}
override fun insert(uri: Uri, values: ContentValues): Uri? {
return null
}
override fun delete(uri: Uri, selection: String, selectionArgs: Array<String>): Int {
return 0
}
override fun update(uri: Uri, values: ContentValues, selection: String, selectionArgs: Array<String>): Int {
return 0
}
}
3.获取aidl
对象这么搞
private aidl对象 parseAidlService() {
try {
final Uri aidlUri = Uri.parse("content://********");
final ContentResolver resolver = context.getContentResolver();
final Cursor cursor = resolver.query(aidlUri , null, null, new String[]{这里可以搞个条件参数}, null);
aidl对象 aidlService = null;
if (cursor != null) {
aidlService = aidl对象.Stub.asInterface(getBinder(cursor));
cursor.close();
}
if (aidlService != null) {
return aidlService;
}
} catch (Exception ignored) {
}
return null;
}
private static IBinder getBinder(Cursor cursor) {
Bundle extras = cursor.getExtras();
return extras.getBinder("binder");
}
aidl
文件方法声明时是可以指定标号的,比如下面这种写法。也许极少数人意识到过,aidl
文件的方法是存在标号的,默认标号以定义方法的顺序为依据,赋值后则赋予的值代表标号。Server
和Client
中aidl
文件有区别时,尤其需要注意,我遇到过有人加aidl
方法直接加在文件中间。aidl
方法的执行主要依靠这个标号,如果标号和方法对不上则会产生问题,会产生什么问题当做叔对你的考验。interface IAidlInterface {
void basicTypes(int anInt) =1;
}
什么时候用in
、out
、inout
,client
端能改server
端不能改的参数用in
,反过来用out
,两端都想改的用inout
。
实际不需要记,叔教你,先什么都不加,编译不过会报错的,报错了就加inout
,这和直接用public
一样,等到你真正明白之后,再去使用最小限度吧。
什么时候用oneway
,大多数用不上。不关心server
端执行情况的就加这个。但是联系生活,就算真的不关心,也没必要表现出来,我们假装关心一下,也就是不加oneway
。
方法数据传输量大怎么办,aidl
跨进程通信时有数据量限制,太大了受不了。
题外话,为什么要限制大小,限制大小就是限制时间,数据量大传输时间就长,假装aidl
实现是内存共享,空间时间就那么大那么多,不能让你全占了。就跟去医院挂号一样,就一个医生让你用一天,别人看不了病了。
回归正题,数据量就是大怎么办,也能办,分片传输
。
分片实现类参照类android.content.pm.ParceledListSlice
或者android.content.pm.StringParceledListSlice
实现,它可以分片传输List
,是隐藏类,但是可以用,可以使用这个带隐藏类的库。