也许你从不曾了解过安卓AIDL

2023-12-26 13:09:57

事先声明,本文所有说法均是临时起意,没有完整代码给予参考

AIDL作用

AIDL(Android Interface Definition Language)是一种用于定义和实现跨进程通信接口的语言。它是 Android 系统中用于进程间通信(IPC)的一种机制,允许一个进程向另一个进程发送请求并获取响应。

从介绍中可与看到,AIDL是被用作跨进程传输数据的一种方式。

有很多人说我开发安卓几年就没用个AIDL,其实也正常,大多APP只有一个进程,用不上这玩意。一个APP里多个进程的操作多数用来做些花里胡哨的操作,比如进程守护、加大内存。但是这里叔劝你一句,没必要,叔怕你把握不住。

回归本质,就让AIDL做它该做的事情,跨进程通信,跨APP通信

AIDL有哪些竞品(我想列哪些就列哪些)

  • Socket
  • 文件共享
  • startActivitystartServiceBroadcastReceiverContentProvider

为什么选用AIDL

  • Socket文件共享相比,实现简单。(虽然在很久很久以前,AIDL是手动实现的)
  • 跟四大组件相比,异步回调简单,这里也许很多人虽然用到过,但是很少意识到四大组件的异步回调

AIDL别人都怎么用

  1. 定义个aidl文件,声明几个方法
  2. 再搞个Service,在onBind里返回个binder对象
  3. 在某个方法里调用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文件的方法是存在标号的,默认标号以定义方法的顺序为依据,赋值后则赋予的值代表标号。
    这在ServerClientaidl文件有区别时,尤其需要注意,我遇到过有人加aidl方法直接加在文件中间。
    aidl方法的执行主要依靠这个标号,如果标号和方法对不上则会产生问题,会产生什么问题当做叔对你的考验。
interface IAidlInterface {
    void basicTypes(int anInt) =1;
}
  • 什么时候用inoutinoutclient端能改server端不能改的参数用in,反过来用out,两端都想改的用inout
    实际不需要记,叔教你,先什么都不加,编译不过会报错的,报错了就加inout,这和直接用public一样,等到你真正明白之后,再去使用最小限度吧。

  • 什么时候用oneway,大多数用不上。不关心server端执行情况的就加这个。但是联系生活,就算真的不关心,也没必要表现出来,我们假装关心一下,也就是不加oneway

  • 方法数据传输量大怎么办,aidl跨进程通信时有数据量限制,太大了受不了。
    题外话,为什么要限制大小,限制大小就是限制时间,数据量大传输时间就长,假装aidl实现是内存共享,空间时间就那么大那么多,不能让你全占了。就跟去医院挂号一样,就一个医生让你用一天,别人看不了病了。
    回归正题,数据量就是大怎么办,也能办,分片传输
    分片实现类参照类android.content.pm.ParceledListSlice或者android.content.pm.StringParceledListSlice实现,它可以分片传输List,是隐藏类,但是可以用,可以使用这个带隐藏类的库

文章来源:https://blog.csdn.net/qq_26413249/article/details/135215270
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。