Android AIDL使用
创始人
2024-05-30 10:02:01
0

一. 概述

Android 接口定义语言 (AIDL) 与您可能使用过的其他接口语言 (IDL) 类似。您可以利用它定义客户端与服务均认可的编程接口,以便二者使用进程间通信 (IPC) 进行相互通信。在 Android 中,一个进程通常无法访问另一个进程的内存。因此,为进行通信,进程需将其对象分解成可供操作系统理解的原语,并将其编组为可供您操作的对象。

二. 定义 AIDL 接口

在构建每个包含 .aidl 文件的应用时,Android SDK 工具会生成基于该 .aidl 文件的 IBinder 接口,并将其保存到项目的 gen/ 目录中。服务必须视情况实现 IBinder 接口。然后,客户端应用便可绑定到该服务,并调用 IBinder 中的方法来执行 IPC

AIDL 使用一种简单语法,允许您通过一个或多个方法(可接收参数和返回值)来声明接口。参数和返回值可为任意类型,甚至是 AIDL 生成的其他接口。

您必须使用 Java 编程语言构建 .aidl 文件。每个 .aidl 文件均须定义单个接口,并且只需要接口声明和方法签名。

默认情况下,AIDL 支持下列数据类型:

1. Java 编程语言中的8中基本类型(如 byte  char  boolean  short   int   float  long   double)

2. CharSequence类型,如String、SpannableString等;

3. List
List 中的所有元素必须是以上列表中支持的数据类型,或者您所声明的由 AIDL 生成的其他接口或 Parcelable 类型。您可选择将 List 用作“泛型”类(例如,List)。尽管生成的方法旨在使用 List 接口,但另一方实际接收的具体类始终是 ArrayList。

4. Map
Map 中的所有元素必须是以上列表中支持的数据类型,或者您所声明的由 AIDL 生成的其他接口或 Parcelable 类型。不支持泛型 Map(如 Map 形式的 Map)。尽管生成的方法旨在使用 Map 接口,但另一方实际接收的具体类始终是 HashMap。

5. 所有Parceable接口的实现类,因为跨进程传输对象时,本质上是序列化与反序列化的过程;

6. AIDL接口,所有的AIDL接口本身也可以作为可支持的数据类型;

有两个需要注意的地方:

1、在Java中,如果一个对象和引用它的类在同一个package下,是不需要导包的,即不需要import,而在AIDL中自定义的Parceable对象和AIDL接口定义的对象必须在所引用的AIDL文件中显式import进来,不管这些对象和所引用它们的AIDL文件是否在同一个包下

2、如果AIDL文件中使用到自定义的Parceable对象,则必须再创建一个与Parceable对象同名的AIDL文件,声明该对象为Parceable类型,并且根据上一条语法规定,在AIDL文件中进行显式import。

定义服务接口时,请注意:

1)方法可带零个或多个参数,返回值或空值方法前不能用 public/private/protected/final 等关键字修饰.
2)所有非原基本类型参数均需要指示数据走向的方向标记。这类标记可以是 in、out 或 inout(见下方示例) , 比如Parcelable 对象.

3)定向tag正确使用
AIDL中,除了基本数据类型,其他类型的方法参数都必须标上数据在跨进程通信中的流向:in、out或inout:

1、in表示输入型参数:只能由客户端流向服务端,服务端收到该参数对象的完整数据,但服务端对该对象的后续修改不会影响到客户端传入的参数对象;

2、out表示输出型参数:只能由服务端流向客户端,服务端收到该参数的空对象,服务端对该对象的后续修改将同步改动到客户端的相应参数对象;

3、inout表示输入输出型参数:可在客户端与服务端双向流动,服务端接收到该参数对象的完整数据,且服务端对该对象的后续修改将同步改动到客户端的相应参数对象;

如果tag用的inout的话,在写自定义的Parcelable类时,必须要重写此方法,不然就会报错

public void readFromParcel(Parcel parcel)

定向tag需要一定的开销,根据实际需要去确定选择什么tag,不能滥用。
 

写到这里也顺便复习一下 Parcelable 基础知识

Parcelable 是 Android 特有的序列化接口:

public interface Parcelable {//writeToParcel() 方法中的参数,用于标识当前对象作为返回值返回//有些实现类可能会在这时释放其中的资源public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001;//writeToParcel() 方法中的第二个参数,它标识父对象会管理内部状态中重复的数据public static final int PARCELABLE_ELIDE_DUPLICATES = 0x0002;//用于 describeContents() 方法的位掩码,每一位都代表着一种对象类型public static final int CONTENTS_FILE_DESCRIPTOR = 0x0001;//描述当前 Parcelable 实例的对象类型//比如说,如果对象中有文件描述符,这个方法就会返回上面的 CONTENTS_FILE_DESCRIPTOR//其他情况会返回一个位掩码public int describeContents();//将对象转换成一个 Parcel 对象//参数中 dest 表示要写入的 Parcel 对象//flags 表示这个对象将如何写入public void writeToParcel(Parcel dest, int flags);//实现类必须有一个 Creator 属性,用于反序列化,将 Parcel 对象转换为 Parcelable public interface Creator {public T createFromParcel(Parcel source);public T[] newArray(int size);}//对象创建时提供的一个创建器public interface ClassLoaderCreator extends Creator {//使用类加载器和之前序列化成的 Parcel 对象反序列化一个对象public T createFromParcel(Parcel source, ClassLoader loader);}
}

写一个自定义的ParcelableObj类

public class ParcelableObj implements Parcelable {//元素nameprivate String mName;//构造法方法public ParcelableObj(String name){mName = name;}protected ParcelableObj(Parcel in) {mName = in.readString();}//序列化@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(mName);}/*内容描述*/@Overridepublic int describeContents() {return 0;}//反序列化public static final Creator CREATOR = new Creator() {//反序列创建对象@Overridepublic ParcelableObj createFromParcel(Parcel in) {return new ParcelableObj(in);}//反序列创建对象数组@Overridepublic ParcelableObj[] newArray(int size) {return new ParcelableObj[size];}};
}

通过writeToParcel将你的对象映射成Parcel对象,再通过createFromParcel将Parcel对象映射成你的对象。也可以将Parcel看成是一个流,通过writeToParcel把对象写到流里面,在通过createFromParcel从流里读取对象,只不过这个过程需要你来实现,因此写的顺序和读的顺序必须一致.

三. 编写AIDL文件

AS中可以通过 new AIDL 自动创建一个aidl文件, 内容根据需求自定义编写.

在AndroidStudio中工程目录的Android视图下,右键new一个AIDL文件,

默认将创建一个与java文件夹同级的aidl文件夹用于存放AIDL文件aidl文件夹下的包名与build.gradle中配置的applicationId一致applicationId默认值是应用的包名

例子一 :普通的基本类型数据

// IMyAidlInterface.aidl
package com.example.myclient;// Declare any non-default types here with import statementsinterface IMyAidlInterface {String querybyID(int n);
}

注意事项:  aidl 接口方法中 不能加 public/ private/ protected/final 修饰符;否则就会报错

例子二:  aidl中 用到了自定义Parcelable对象

new 一个完整的app工程, 然后在new 一个 AIDL文件, 工程结构图如下:

PathParceTest.java  implement 实现  Parcelable类

public class PathParceTest implements Parcelable

对于用到自定义Parcelable对象的aidl文件, 创建的规则如下:

1.  自定义的Parcelable对象和AIDL对象必须要显示的import进来,不管他们是否和当前的AIDL文件位于同一个包内.

2. 如果AIDL文件中用到了自定义的Parcelable对象, 那么必须新建一个和它同名的AIDL文件, 并在其中声明它为Parcelable类型.

第2条在代码中体现如下:

比如ITest.aidl 用到了  PathParceTest对象, 那么我们先得写一个PathParceTest类, 然后创建 一个同名的PathParceTest.aidl文件

 上面是创建AIDL文件的语法规则, 按照规则书写代码即可,不然会报错.

对于例子二, 假如你在服务端已经写好了这些aidl代码, 现在要拷贝到客户端, 根据规则, 创建的aidl 必须保持包名一致拷贝过去,  但是你的PathParceTest.java是在服务端的src/main/java/com.example.myaidl/ 路径下,   如果要拷贝过去的话, 文件包名(路径名)在客户端又得新建,然后把PathParceTest.java放置在此路径下.  那么客户端的代码结构非常的难看.

那么,有没有什么更好优化解决办法呢?目的把aidl包所有文件整体拷贝就完事

如果我们把PathParceTest.java放置到同aidl包下,  在编译的时候会报错,提示这个类找不到.

 原因:

我们是在src/main/aidl文件夹下创建PathParceTest.java的,实际上这将因为找不到PathParceTest.java而报错,因为在AndroidStudio中使用Gradle构建项目时,默认是在src/main/java文件夹中查找java文件的,如果把PathParceTest.java放在src/main/aidl对应包名下,自然就会找不到这个文件了,所以需要修改app的build.gradle文件,在sourceSets下添加对应的源文件路径,即src/main/aidl

android {compileSdkVersion 33//加上这段代码 把 src/main/aidl/路径下的java文件也编译进来sourceSets {main {java.srcDirs = ["src/main/java", "src/main/aidl"]}}//加上这段代码 把 src/main/aidl/路径下的java文件也编译进来defaultConfig {applicationId "com.example.myaidl"minSdkVersion 16targetSdkVersion 33versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"................

这样子就解决了上述的问题, 当然客户端中也得加上这段代码, 接下来我们就可以直接拷贝整个aidl包了.

四. 总结

        本文主要讲解了AIDL的语法规则和创建AIDL文件的注意点, 特别是引用自定义Parcelable对象的aidl文件创建注意事项. 也是为后续写 进程间通信机制 相关的文章做个铺垫.


 

相关内容

热门资讯

有关先秦诸子百家的书 有关先秦诸子百家的书《论语》《道德经》《吕氏春秋》《韩非子》《孙子兵法》……
李寻欢为什么咳嗽 李寻欢为什么咳嗽容易引起女人的关爱.他有病啊 因为古龙希望他有病 而且还是咳嗽~就是给他刻化的...
兴业银锡相关公司新增一项190... (转自:快查一企业中标了)快查APP显示,兴业银锡相关公司赤峰宇邦矿业有限公司于2025年6月16日...
我的生日是每年的农历 6月7号... 我的生日是每年的农历 6月7号 那2021年阴历是多少号 麻烦好心人跟我说下?阴历和农历一样,都是六...
三达膜(688101.SH):... 2025年6月16日,三达膜(688101.SH)公告称,公司召开第五届董事会第六次会议,审议通过了...
拉卡拉:正在筹划H股上市事项 ... 中证智能财讯拉卡拉(300773)6月16日晚间公告,公司目前正在筹划境外发行股份(H股)并在香港联...
特朗普集团推出T1智能手机:售...   炒股就看金麒麟分析师研报,权威,专业,及时,全面,助您挖掘潜力主题机会! 财联社6月16日讯(...
德林控股发盈喜 预计年度溢利同... 观点网讯:6月16日,德林控股在香港公告,预计截至2025年3月31日止年度溢利同比增加约10.1%...
伊利、京东火速入局,“苏超”商... “苏超”的商业价值、文旅经济价值仍在持续释放。 202...
《河北日报》报道唐山丨新农人奏... 转自:唐山广播电视台唐山市推动青年在农村施展才华新农人奏响田野创业曲□ 河北日报记者 师源 王育民 ...
俄外交部:美方取消俄美双边磋商... 格隆汇6月16日|据央视,俄罗斯外交部发言人扎哈罗娃在回答媒体关于俄美磋商前景的提问时表示,截至目前...
5月70城房价同比降幅收窄,商... 21世纪经济报道记者李莎 北京报道 6月16日,国家统计局发布5月房地产数据。数据显示,5月70个大...
中国作协“作家活动周”启幕 聚... 转自:千龙网由中国作家协会主办的第12期“作家活动周”6月16日在京启幕,本期活动以“中国文学新力量...
今年全国节能宣传周聚焦“节能增... 转自:中国政府采购报【行业动态】今年全国节能宣传周聚焦“节能增效 焕‘新’引领”本报讯 国家发展改革...
这个是什么字?繁体的 这个是什么字?繁体的就是面条的那个面面粉的面,面球的面。面 miàn 就是由小麦磨成的粉
科技赋能 各地夏收夏种高效推进 眼下正值“三夏”时节,各地依托科技赋能,助力夏收夏种夏管提速增效。截至15日,山东小麦已收5600多...
美股异动|Meta盘初涨超3%... 格隆汇6月16日|Meta Platforms(META.US)盘初涨超3%。消息面上,Meta准备...
以色列军方说已摧毁伊朗约三分之... 来源:新华社新华社耶路撒冷6月16日电以色列国防军发言人埃菲·戴弗林16日发表声明说,自13日发动袭...
魔兽世界盗贼如何在战斗中隐身 魔兽世界盗贼如何在战斗中隐身魔兽世界盗贼如何在战斗中隐身,不是强隐。比如给致盲以后等一会就能隐身了是...
伤害不大但启示深刻 转自:中国政府采购报【行业观察】伤害不大但启示深刻——美的北美空调召回事件之政府采购观察■ 吴敏近日...