当前位置: 首页 > news >正文

[Android AIDL] --- AIDL原理简析

上一篇文章已经讲述了如何在Android studio中搭建基于aidl的cs模型框架,只是用起来了,这次对aidl及cs端如何调用的原理进行简单分析

1 创建AIDL文件

AIDL 文件可以分为两类。
一类是用来定义接口方法,声明要暴露哪些接口给客户端调用;
一类用来声明实现了 Parcelable 接口的数据类型,以供其他 AIDL 文件使用那些非默认支持的数据类型。
在 AIDL 文件中需要明确标明引用到的数据类型所在的包名,即使两个文件处在同个包名下。
默认情况下,AIDL 支持下列数据类型:

八种基本数据类型:byte、charshortintlongfloatdouble、boolean
String,CharSequence
List类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象

客户端和服务端都需要创建,我们先在server端中创建,然后复制到client端即可。在 Android Studio 中右键点击新建一个 AIDL 文件,如图所示:
在这里插入图片描述
创建完成后,系统就会默认创建一个 aidl 文件夹,文件夹下的目录结构即是工程的包名,AIDL 文件就在其中。如图所示:
在这里插入图片描述
文件中会有一个默认方法,可以删除掉,也可以新增其他方法。

2 实现接口

创建或修改过 AIDL 文件后需要 build 下工程,Android SDK 工具会生成以 .aidl 文件命名的 .java 接口文件(例如,IRemoteService.aidl 生成的文件名是 IRemoteService.java),在进程间通信中真正起作用的就是该文件。生成的接口包含一个名为 Stub 的子类(例如,IRemoteService.Stub),该子类是其父接口的抽象实现,并且会声明 AIDL 文件中的所有方法。
如要实现 AIDL 生成的接口,请实例化生成的 Binder 子类(例如,IRemoteService.Stub),并实现继承自 AIDL 文件的方法。
以下是使用匿名内部类实现 IRemoteService 接口的示例:

private final IRemoteService.Stub binder = new IRemoteService.Stub() {public int getPid(){return Process.myPid();}public void basicTypes(int anInt, long aLong, boolean aBoolean,float aFloat, double aDouble, String aString) {// Does nothing}
};

现在,binder 是 Stub 类的一个实例(一个 Binder),其定义了服务端的 RPC 接口。

3 server端公开接口

在为服务端实现接口后,需要向客户端公开该接口,以便客户端进行绑定。创建 Service 并实现 onBind(),从而返回生成的 Stub 的类实例。以下是服务端的示例代码:

public class RemoteService extends Service {private final String TAG = "RemoteService";@Overridepublic void onCreate() {super.onCreate();}@Overridepublic IBinder onBind(Intent intent) {// Return the interfaceLog.d(TAG, "onBind");return binder;}private final IRemoteService.Stub binder = new IRemoteService.Stub() {public int getPid() {return Process.myPid();}public void basicTypes(int anInt, long aLong, boolean aBoolean,float aFloat, double aDouble, String aString) {Log.d(TAG, "basicTypes anInt:" + anInt + ";aLong:" + aLong + ";aBoolean:" + aBoolean + ";aFloat:" + aFloat + ";aDouble:" + aDouble + ";aString:" + aString);}};
}

我们还需要在 Manefest 文件中注册我们创建的这个 Service,否则客户端无法绑定服务。

      <serviceandroid:name=".RemoteService"android:enabled="true"android:exported="true"><intent-filter><action android:name="com.example.aidl"/><category android:name="android.intent.category.DEFAULT"/></intent-filter></service>

4 client 端调用IPC方法

当客户端(如 Activity)调用 bindService() 以连接此服务时,客户端的 onServiceConnected() 回调会接收服务端的 onBind() 方法所返回的 binder 实例。
客户端还必须拥有接口类的访问权限,因此如果客户端和服务端在不同应用内,则客户端应用的 src/ 目录内必须包含 .aidl 文件(该文件会生成 android.os.Binder 接口,进而为客户端提供 AIDL 方法的访问权限)的副本。所以我们需要把服务端的 aidl 文件夹整个复制到客户端的 java 文件夹同个层级下,不需要改动任何代码。
当客户端在 onServiceConnected() 回调中收到 IBinder 时,它必须调用 IRemoteService.Stub.asInterface(service),以将返回的参数转换成 IRemoteService 类型。例如:

IRemoteService iRemoteService;
private ServiceConnection mConnection = new ServiceConnection() {// Called when the connection with the service is establishedpublic void onServiceConnected(ComponentName className, IBinder service) {// Following the example above for an AIDL interface,// this gets an instance of the IRemoteInterface, which we can use to call on the serviceiRemoteService = IRemoteService.Stub.asInterface(service);}// Called when the connection with the service disconnects unexpectedlypublic void onServiceDisconnected(ComponentName className) {Log.e(TAG, "Service has unexpectedly disconnected");iRemoteService = null;}
};

获得了 iRemoteService 对象,我们就可以调用 AIDL 中定义的方法了。如要断开连接,可以调用unbindService() 方法。以下是客户端的示例代码:

public class MainActivity extends AppCompatActivity {private final String TAG = "ClientActivity";private IRemoteService iRemoteService;private Button mBindServiceButton;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mBindServiceButton = findViewById(R.id.btn_bind_service);mBindServiceButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String text = mBindServiceButton.getText().toString();if ("Bind Service".equals(text)) {Intent intent = new Intent();intent.setAction("com.example.aidl");intent.setPackage("com.example.aidl.server");bindService(intent, mConnection, Context.BIND_AUTO_CREATE);} else {unbindService(mConnection);mBindServiceButton.setText("Bind Service");}}});}ServiceConnection mConnection = new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {Log.d(TAG, "onServiceDisconnected");iRemoteService = null;}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {Log.d(TAG, "onServiceConnected");iRemoteService = IRemoteService.Stub.asInterface(service);try {int pid = iRemoteService.getPid();int currentPid = Process.myPid();Log.d(TAG, "currentPID: " + currentPid + ", remotePID: " + pid);iRemoteService.basicTypes(12, 123, true, 123.4f, 123.45,"服务端你好,我是客户端");} catch (RemoteException e) {e.printStackTrace();}mBindServiceButton.setText("Unbind Service");}};
}

5 通过IPC传递对象

除了上面默认支持的数据类型,AIDL 还可以传递对象,但是该类必须实现 Parcelable 接口。而该类是两个应用间都需要使用到的,所以也需要在 AIDL 文件中声明该类,为了避免出现类名重复导致无法创建 AIDL 文件的错误,这里需要先创建 AIDL 文件,之后再创建类。
先在服务端新建一个 AIDL 文件,比如 Rect.aidl,示例如下:

// Rect.aidl
package com.example.aidl.server;// Declare Rect so AIDL can find it and knows that it implements
// the parcelable protocol.
parcelable Rect;

然后就可以创建 Rect 类了,并使之实现 Parcelable 接口。示例代码如下:

public class Rect implements Parcelable {private int left;private int top;private int right;private int bottom;public Rect(int left, int top, int right, int bottom) {this.left = left;this.top = top;this.right = right;this.bottom = bottom;}public static final Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect>() {public Rect createFromParcel(Parcel in) {return new Rect(in);}public Rect[] newArray(int size) {return new Rect[size];}};private Rect(Parcel in) {readFromParcel(in);}@Overridepublic void writeToParcel(Parcel out, int flags) {out.writeInt(left);out.writeInt(top);out.writeInt(right);out.writeInt(bottom);}public void readFromParcel(Parcel in) {left = in.readInt();top = in.readInt();right = in.readInt();bottom = in.readInt();}@Overridepublic int describeContents() {return 0;}@NonNull@Overridepublic String toString() {return "Rect[left:" + left + ",top:" + top + ",right:" + right + ",bottom:" + bottom + "]";}
}

这样我们就可以在之前创建的 IRemoteService.aidl 中新增一个方法来传递 Rect 对象了,示例代码如下:

// IRemoteService.aidl
package com.example.aidl.server;
import com.example.aidl.server.Rect;// Declare any non-default types here with import statementsinterface IRemoteService {/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,double aDouble, String aString);int getPid();void addRectInOut(inout Rect rect);
}

注意这里需要明确导包:

import com.example.aidl.server.Rect;

然后将新增的 Rect.aidl 文件和 Rect.java 文件还有修改的 IRemoteService.aidl 文件同步到客户端相同路径下,如图所示:
在这里插入图片描述
build 下工程,就可以在客户端调用到该 addRectInOut 方法了。示例代码如下:

    ServiceConnection mConnection = new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {iRemoteService = IRemoteService.Stub.asInterface(service);try {iRemoteService.addRectInOut(new Rect(1, 2, 3, 4));} catch (RemoteException e) {e.printStackTrace();}}};

相关文章:

[Android AIDL] --- AIDL原理简析

上一篇文章已经讲述了如何在Android studio中搭建基于aidl的cs模型框架&#xff0c;只是用起来了&#xff0c;这次对aidl及cs端如何调用的原理进行简单分析 1 创建AIDL文件 AIDL 文件可以分为两类。 一类是用来定义接口方法&#xff0c;声明要暴露哪些接口给客户端调用&#…...

企业的固定资产管理怎么操作

一家拥有多台大型设备的工厂&#xff0c;这些设备需要定期进行保养和维护&#xff0c;以确保其正常运转。而企业内部员工由于专业知识和技能的不同&#xff0c;需要分工协作才能更好地完成各项工作任务。因此&#xff0c;在设备资产管理方面&#xff0c;如何实现高效、便捷、透…...

Rust 进阶学习

Rust 进阶学习 文章目录 Rust 进阶学习所有权作用域移动和克隆涉及函数的所有权机制涉及参数的所有权涉及返回值的所有权 引用和租借可变引用 枚举类枚举成员的属性枚举匹配 结构体结构体方法结构体关联函数 错误处理不可恢复错误可恢复错误 Rust代码组织管理Module默认的Modul…...

保护网站安全:学习蓝莲花的安装和使用,复现跨站脚本攻击漏洞及XSS接收平台

这篇文章旨在用于网络安全学习&#xff0c;请勿进行任何非法行为&#xff0c;否则后果自负。 环境准备 一、XSS基础 1、反射型XSS 攻击介绍 原理 攻击者通过向目标网站提交包含恶意脚本的请求&#xff0c;然后将该恶意脚本注入到响应页面中&#xff0c;使其他用户在查看…...

Redis——如何解决redis穿透、雪崩、击穿问题

目录 一、查询商品信息的常规代码示例二、缓存击穿2.1、缓存击穿的理解2.2、缓存击穿的解决方案2.3、解决缓存击穿的代码示例 三、缓存雪崩3.1、缓存雪崩的理解3.2、缓存雪崩的解决方案3.2.1、缓存集中过期的情况3.2.2、缓存服务器宕机的情况3.2.3、缓存服务器断电的情况 3.3、…...

MySQL一行记录是如何存储的?

目录 MySQL的数据存放在哪个文件&#xff1f; 表空间文件的结构是怎么样的&#xff1f; 1、行&#xff08;row&#xff09; 2、页&#xff08;page&#xff09; 3、区&#xff08;extent&#xff09; 4、段&#xff08;segment&#xff09; InnoDB 行格式有哪些&#xf…...

[element-ui] el-tree全部展开与收回

shrinkTreeNode () {// 改变一个全局变量this.treeStatus !this.treeStatus;// 改变每个节点的状态this.changeTreeNodeStatus(this.$refs.attrList.store.root); },// 改变节点的状态 changeTreeNodeStatus (node) {node.expanded this.treeStatus;for (let i 0; i < no…...

git 统计(命令)

查询某人某个时刻提交了多少代码 added 添加代码 removed 删除代码 total 总代码 git log --author刘俊秦 --since2023-08-01 00:00:00 --until2023-08-23 23:00:00 --prettytformat: --numstat | awk { add $1; subs $2; loc $1 - $2 } END { printf "added lines: %s…...

斐波那契1(矩阵快速幂加速递推,斐波那契前n项平方和)

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 Keven 特别喜欢斐波那契数列&#xff0c;已知 fib11fib_11fib1​1&#xff0c;fib21fib_21fib2​1&#xff0c;对于 n>3n>3n>3&#xff0c;fibnfibn−2fibn−1fib_{n}fib_{n-2}fib_{n…...

minikube mac 启动

系统信息如下 最开始使用的minikube是1.22.0版本&#xff0c;按照如下命令启动&#xff1a; minikube start --memory7851 --cpus4 --image-mirror-countrycn遇到了下面一些问题&#xff1a; 1、拉取coredns:v1.8.0镜像失败 Error response from daemon: manifest for regis…...

从零开始学习 Java:简单易懂的入门指南之查找算法及排序算法(二十)

查找算法及排序算法 常见的七种查找算法&#xff1a;1. 基本查找2. 二分查找3. 插值查找4. 斐波那契查找5. 分块查找6. 哈希查找7. 树表查找 四种排序算法&#xff1a;1. 冒泡排序1.1 算法步骤1.2 动图演示1.3 代码示例 2. 选择排序2.1 算法步骤2.2 动图演示 3. 插入排序3.1 算…...

非煤矿山风险监测预警算法 yolov8

非煤矿山风险监测预警算法通过yolov8网络模型深度学习算法框架&#xff0c;非煤矿山风险监测预警算法在煤矿关键地点安装摄像机等设备利用智能化视频识别技术&#xff0c;能够实时分析人员出入井口的情况&#xff0c;人数变化并检测作业状态。YOLO的结构非常简单&#xff0c;就…...

Ansible学习笔记(一)

1.什么是Ansible 官方网站&#xff1a;https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html Ansible是一个配置管理和配置工具&#xff0c;类似于Chef&#xff0c;Puppet或Salt。这是一款很简单也很容易入门的部署工具&#xff0c;它使用SS…...

2024毕业设计选题指南【附选题大全】

title: 毕业设计选题指南 - 如何选择合适的毕业设计题目 date: 2023-08-29 categories: 毕业设计 tags: 选题指南, 毕业设计, 毕业论文, 毕业项目 - 如何选择合适的毕业设计题目 当我们站在大学生活的十字路口&#xff0c;毕业设计便成了我们面临的一项重要使命。这不仅是对我们…...

Error: PostCSS plugin autoprefixer requires PostCSS 8 问题解决办法

报错&#xff1a;Error: PostCSS plugin autoprefixer requires PostCSS 8 原因&#xff1a;autoprefixer版本过高 解决方案&#xff1a; 降低autoprefixer版本 执行&#xff1a;npm i postcss-loader autoprefixer8.0.0...

pymongo通过oplog获取数据(mongodb)

使用 MongoDB 的 oplog&#xff08;操作日志&#xff09;进行数据同步是高级的用法&#xff0c;主要用于复制和故障恢复。需要确保源 MongoDB 实例是副本集的一部分&#xff0c;因为只有副本集才会维护 oplog。 以下是简化的步骤&#xff0c;描述如何使用 oplog 进行数据同步&…...

MySQL数据备份与恢复

备份的主要目的&#xff1a; 备份的主要目的是&#xff1a;灾难恢复&#xff0c;备份还可以测试应用、回滚数据修改、查询历史数据、审计等。 日志&#xff1a; MySQL 的日志默认保存位置为&#xff1a; /usr/local/mysql/data##配置文件 vim /etc/my.cnf [mysqld] ##错误日志…...

基于ssm+vue汽车售票网站源码和论文

基于ssmvue汽车售票网站源码和论文088 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让…...

【List】List集合有序测试案例:ArrayList,LinkedList,Vector(123)

List是有序、可重复的容器。 有序&#xff1a; List中每个元素都有索引标记。可以根据元素的索引标记(在List中的位置)访问 元素&#xff0c;从而精确控制这些元素。 可重复&#xff1a; List允许加入重复的元素。更确切地讲&#xff0c;List通常允许满足 e1.equals(e2) 的元素…...

【javaweb】学习日记Day6 - Mysql 数据库 DDL DML

之前学习过的SQL语句笔记总结戳这里→【数据库原理与应用 - 第六章】T-SQL 在SQL Server的使用_Roye_ack的博客-CSDN博客 目录 一、概述 1、如何安装及配置路径Mysql&#xff1f; 2、SQL分类 二、DDL 数据定义 1、数据库操作 2、IDEA内置数据库使用 &#xff08;1&…...

OpenClaw自动化测试框架:百川2-13B驱动的CI/CD辅助方案

OpenClaw自动化测试框架&#xff1a;百川2-13B驱动的CI/CD辅助方案 1. 为什么选择OpenClaw做测试自动化 去年我在重构一个中型前端项目时&#xff0c;遇到了测试覆盖率不足的老问题。手动补测试用例不仅耗时&#xff0c;还经常遗漏边界条件。当我尝试用传统测试生成工具时&am…...

告别卡顿!用UE5关卡流送(Level Streaming)优化你的开放世界游戏性能

告别卡顿&#xff01;用UE5关卡流送&#xff08;Level Streaming&#xff09;优化你的开放世界游戏性能 当玩家在广袤的开放世界中自由探索时&#xff0c;没有什么比突然的加载卡顿或帧率骤降更能破坏沉浸感了。作为UE5开发者&#xff0c;我们常常面临一个两难选择&#xff1a;…...

从遥控器到智能家居:拆解一个25年前的NEC协议,如何至今仍在‘发光发热’

NEC红外协议&#xff1a;穿越25年的技术生命力与智能家居新应用 当你在智能音箱上说出"打开客厅空调"时&#xff0c;可能正触发着一套诞生于上世纪90年代的技术标准。NEC红外协议这个最初为电视遥控器设计的通信规范&#xff0c;如今仍在全球数以亿计的设备中默默工…...

Python多线程真能并行了吗?(GIL绕过技术全图谱:subprocess/numba/multiprocessing/cython/rustpy)

第一章&#xff1a;Python无锁GIL环境下的并发模型面试题汇总Python 的全局解释器锁&#xff08;GIL&#xff09;长期被视为多线程并发的瓶颈&#xff0c;但近年来随着 CPython 3.13 引入实验性无锁 GIL&#xff08;--without-pymalloc 配合 --with-per-object-gil 原型&#x…...

如何用SVGnest提升材料利用率:从问题到解决方案的完整指南

如何用SVGnest提升材料利用率&#xff1a;从问题到解决方案的完整指南 【免费下载链接】SVGnest An open source vector nesting tool 项目地址: https://gitcode.com/gh_mirrors/sv/SVGnest 制造业材料浪费的隐形成本&#xff1a;您的企业是否正在损失30%利润&#xff…...

资源监控告警:OpenClaw+Qwen3-32B镜像守护个人服务器

资源监控告警&#xff1a;OpenClawQwen3-32B镜像守护个人服务器 1. 为什么需要智能化的个人服务器监控&#xff1f; 去年我的个人服务器连续宕机三次——第一次因为内存泄漏导致OOM崩溃&#xff0c;第二次被挖矿程序占用全部CPU资源&#xff0c;第三次则是磁盘写满后无人察觉…...

Qwen3-TTS-VoiceDesign实战案例:用‘撒娇稚嫩萝莉声’描述生成高拟真TTS音频

Qwen3-TTS-VoiceDesign实战案例&#xff1a;用‘撒娇稚嫩萝莉声’描述生成高拟真TTS音频 1. 项目概述与核心价值 Qwen3-TTS-VoiceDesign是一个让人惊艳的语音合成模型&#xff0c;它最大的特点就是能用简单的文字描述&#xff0c;生成你想要的任何声音风格。想象一下&#xf…...

CasRel模型LaTeX学术论文辅助工具:自动提取相关工作和贡献

CasRel模型LaTeX学术论文辅助工具&#xff1a;自动提取相关工作和贡献 每次打开一篇新的学术论文&#xff0c;尤其是那些动辄几十页的综述或顶会文章&#xff0c;你是不是也有点头大&#xff1f;密密麻麻的文字里&#xff0c;最关键的信息——“别人做了什么”、“他们有什么不…...

FlowState Lab模型微调教程:使用自定义数据集训练专属波动模型

FlowState Lab模型微调教程&#xff1a;使用自定义数据集训练专属波动模型 1. 学习目标与前置准备 想为特定领域打造专属的波动预测模型吗&#xff1f;本文将带你完成从数据准备到模型评估的全流程。学完本教程&#xff0c;你将能够&#xff1a; 准备符合要求的时序/空间序列…...

Flutter弹窗层级混乱?手把手教你用Overlay管理多个弹窗的显示顺序

Flutter弹窗层级管理实战&#xff1a;用Overlay解决多弹窗叠加难题 在移动应用开发中&#xff0c;弹窗是用户交互的重要组成部分。但当多个弹窗同时出现时&#xff0c;开发者常会遇到"哪个弹窗应该显示在最上层"的困扰。想象一下这样的场景&#xff1a;用户正在填写…...