AIDL(Android Interface Definition Language)详解

AIDL的定义

AIDL(Android Interface Definition Language)是Android接口定义语言,用于:

实现进程间通信(IPC)

定义客户端和服务端之间的通信接口

允许不同应用程序或同一应用程序的不同进程之间调用方法

AIDL实现原理

AIDL通过Binder机制实现进程间通信。Binder是Android中的一种跨进程通信方式,它使用客户端-服务器模式。在AIDL中,你定义一个接口,编译后会生成一个Java类,这个类中包含了用于IPC的代码。当客户端调用远程方法时,实际上是通过Binder将方法调用和数据打包(序列化)并发送给服务端,服务端接收到后执行相应方法,然后将结果返回给客户端。

客户端进程 Binder驱动 服务端进程 | | | | --- 调用方法 ---> | | | | --- 传递数据 ---> | | | | | | <-- 返回结果 ---- | | <-- 接收结果 ---- | |

AIDL的使用场景

1. 跨应用服务调用
App A需要调用App B提供的功能

例如:第三方支付SDK、地图服务等

2. 系统服务调用
App调用系统服务(电话、短信、定位等)

系统服务通过AIDL向应用暴露接口

AIDL的使用步骤

使用AIDL的典型场景:

你想要你的服务(Service)被多个应用使用,或者你的应用想要使用其他应用的服务。

你需要在同一应用的不同进程间通信(比如你的应用有多进程)。

我们通过几个步骤来理解AIDL:

步骤1:定义AIDL接口
步骤2:实现AIDL接口
步骤3:暴露服务给其他进程
步骤4:客户端绑定服务并调用远程方法

注意:由于AIDL是跨进程的,因此数据传递需要序列化。AIDL默认支持一些基本数据类型(int, long, char, boolean, double, String等),如果要传递自定义对象,则需要实现Parcelable接口

步骤1:定义AIDL接口

在Android Studio中,我们可以在main目录下新建一个aidl文件夹,然后在该文件夹下新建包,包名与项目包名相同(或者任意,但建议与项目包名一致)。然后新建一个IAddService.aidl文件。

// IAddService.aidl package com.example.aidldemo; interface IAddService { /** * 计算两个整数的和 */ int add(int a, int b); }

步骤2、步骤3和步骤4:实现AIDL接口+暴露服务给其他进程+客户端绑定服务并调用远程方法

我们需要创建一个Service,在Service中创建一个内部类实现IAddService.Stub,并实现add方法。

具体代码:

1.服务端代码:

首先,创建服务AddService:

public class AddService extends Service { public AddService() { } // 创建IAddService.Stub的实现类 private final IAddService.Stub binder = new IAddService.Stub() { @Override public int add(int a, int b) throws RemoteException { return a + b; } }; //在Service的onBind方法中返回这个IAddService.Stub的实现。 @Override public IBinder onBind(Intent intent) { return binder; } }

2.在AndroidManifest.xml中注册服务,并设置为其他进程可访问(因为默认同一应用内,如果不需要跨应用,可以不用设置exported,但这里我们为了演示跨进程,可以设置exported为true,并设置一个action):

<service android:name=".AddService" android:exported="true" android:process=":remote"> <!-- 这里设置为独立进程,也可以不设置,但为了演示跨进程,我们设置为另一个进程 --> <intent-filter> <action android:name="com.example.aidldemo.AddService" /> </intent-filter> </service>

3.客户端代码:

首先,我们需要将服务端的AIDL文件复制到客户端(如果客户端和服务端是同一个应用,则不需要复制,但如果是不同应用,则需要复制AIDL文件,包括包结构)。

然后,在客户端绑定服务:

public class MainActivity extends AppCompatActivity { private IAddService addService; private boolean isBound = false; private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { // 使用IAddService.Stub.asInterface方法将IBinder转换为IAddService接口 addService = IAddService.Stub.asInterface(service); isBound = true; } @Override public void onServiceDisconnected(ComponentName name) { addService = null; isBound = false; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 绑定服务 Intent intent = new Intent(); intent.setAction("com.example.aidldemo.AddService"); // 从Android 5.0开始,必须显式声明服务所在包名 intent.setPackage("com.example.aidldemo"); // 服务所在应用的包名 bindService(intent, connection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); if (isBound) { unbindService(connection); isBound = false; } } // 调用远程服务的方法 public void onAddClick(View view) { if (isBound) { try { int result = addService.add(5, 3); Toast.makeText(this, "Result: " + result, Toast.LENGTH_SHORT).show(); } catch (RemoteException e) { e.printStackTrace(); } } } }

AIDL的Demo实现

步骤1:创建AIDL文件

在 app/src/main/aidl/com/example/ 目录下创建 IBookManager.aidl:

// IBookManager.aidl package com.example.aidldemo; // 声明要传递的自定义类型 parcelable Book; interface IBookManager { // 添加书籍 void addBook(in Book book); // 获取书籍列表 List<Book> getBookList(); // 基础类型示例 int getBookCount(); }

步骤2:创建可序列化的Book类

// Book.java package com.example.aidldemo; import android.os.Parcel; import android.os.Parcelable; public class Book implements Parcelable { private int id; private String name; private double price; // 构造函数 public Book(int id, String name, double price) { this.id = id; this.name = name; this.price = price; } // Parcelable实现 protected Book(Parcel in) { id = in.readInt(); name = in.readString(); price = in.readDouble(); } public static final Creator<Book> CREATOR = new Creator<Book>() { @Override public Book createFromParcel(Parcel in) { return new Book(in); } @Override public Book[] newArray(int size) { return new Book[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(id); dest.writeString(name); dest.writeDouble(price); } // Getter/Setter public int getId() { return id; } public String getName() { return name; } public double getPrice() { return price; } }

步骤3:创建服务端Service

// BookManagerService.java public class BookManagerService extends Service { private static final String TAG = "BookManagerService"; // 存储书籍的列表(注意使用支持并发操作的CopyOnWriteArrayList) private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>(); // Binder对象,实现AIDL接口 // Binder可以替换为IBookManager.Stub private Binder mBinder = new IBookManager.Stub() { @Override public void addBook(Book book) throws RemoteException { Log.d(TAG, "添加书籍: " + book.getName()); mBookList.add(book); } @Override public List<Book> getBookList() throws RemoteException { Log.d(TAG, "获取书籍列表,当前数量: " + mBookList.size()); return mBookList; } @Override public int getBookCount() throws RemoteException { return mBookList.size(); } }; @Override public IBinder onBind(Intent intent) { Log.d(TAG, "服务被绑定"); return mBinder; } @Override public void onCreate() { super.onCreate(); Log.d(TAG, "服务创建"); // 添加一些初始数据 mBookList.add(new Book(1, "Android开发艺术探索", 79.0)); mBookList.add(new Book(2, "第一行代码", 89.0)); } }

别忘了在在 AndroidManifest.xml 中注册服务:

<service android:name=".BookManagerService" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.example.aidldemo.BOOK_SERVICE" /> </intent-filter> </service>

步骤4:客户端调用

// MainActivity.java public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private IBookManager mBookManager; private boolean mIsBound = false; // 连接服务 private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, "服务连接成功"); // 将IBinder转换为AIDL接口 mBookManager = IBookManager.Stub.asInterface(service); mIsBound = true; // 测试调用 try { // 添加新书 Book newBook = new Book(3, "Kotlin实战", 99.0); mBookManager.addBook(newBook); // 获取书籍列表 List<Book> bookList = mBookManager.getBookList(); for (Book book : bookList) { Log.d(TAG, "书名: " + book.getName() + ", 价格: " + book.getPrice()); } // 获取书籍数量 int count = mBookManager.getBookCount(); Log.d(TAG, "总书籍数量: " + count); // 更新UI runOnUiThread(() -> { Toast.makeText(MainActivity.this, "获取到 " + count + " 本书", Toast.LENGTH_SHORT).show(); }); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "服务断开连接"); mIsBound = false; mBookManager = null; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 绑定服务按钮 Button bindBtn = findViewById(R.id.bind_btn); Button unbindBtn = findViewById(R.id.unbind_btn); Button addBookBtn = findViewById(R.id.add_book_btn); bindBtn.setOnClickListener(v -> bindService()); unbindBtn.setOnClickListener(v -> unbindService()); addBookBtn.setOnClickListener(v -> addNewBook()); } private void bindService() { Intent intent = new Intent(); intent.setAction("com.example.aidldemo.BOOK_SERVICE"); intent.setPackage(getPackageName()); // 指定包名,避免隐式Intent问题 bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } private void unbindService() { if (mIsBound) { unbindService(mConnection); mIsBound = false; Toast.makeText(this, "服务已解绑", Toast.LENGTH_SHORT).show(); } } private void addNewBook() { if (mIsBound && mBookManager != null) { try { Random random = new Random(); Book book = new Book( random.nextInt(1000), "随机书籍" + random.nextInt(100), random.nextDouble() * 100 ); mBookManager.addBook(book); int count = mBookManager.getBookCount(); Toast.makeText(this, "添加成功!当前总数: " + count, Toast.LENGTH_SHORT).show(); } catch (RemoteException e) { e.printStackTrace(); } } else { Toast.makeText(this, "请先绑定服务", Toast.LENGTH_SHORT).show(); } } @Override protected void onDestroy() { super.onDestroy(); if (mIsBound) { unbindService(mConnection); } } }

总结

要点 说明 跨进程通信 主要用于不同进程间的数据交换 接口定义 使用.aidl文件定义通信协议 数据序列化 自定义对象需要实现Parcelable 线程安全 服务端方法可能被并发调用 异常处理 必须处理RemoteException 连接管理 注意绑定/解绑的生命周期 回调监听 使用监听器模式实现事件通知 性能优化 考虑使用连接池、超时、重试机制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1194806.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从入门到精通:3小时掌握CMake链接外部库的核心技术,错过再等一年

第一章&#xff1a;CMake引入第三方库的核心概念在现代C项目开发中&#xff0c;合理引入和管理第三方库是构建可维护、可扩展工程的关键环节。CMake作为跨平台的构建系统生成器&#xff0c;提供了灵活且强大的机制来集成外部依赖。理解其核心概念有助于避免常见的链接错误、头文…

开源CV模型新选择:GPEN人像增强+ModelScope权重集成指南

开源CV模型新选择&#xff1a;GPEN人像增强ModelScope权重集成指南 你是否还在为老旧照片模糊不清、低分辨率人像无法修复而烦恼&#xff1f;市面上的图像增强工具要么效果生硬&#xff0c;要么部署复杂&#xff0c;难以真正落地使用。今天介绍一个开箱即用的解决方案——基于…

2026年河南精铸工匠不锈钢有限公司联系电话推荐:高效对接与合作指引

在当今的商业环境中,高效、准确地联系到目标合作伙伴是项目成功的第一步。对于需要高品质不锈钢标识产品与一体化装饰工程解决方案的企业或个人而言,找到可靠且专业的服务提供商至关重要。河南精铸工匠不锈钢有限公司…

GPEN能否打包成桌面应用?Electron封装可行性研究

GPEN能否打包成桌面应用&#xff1f;Electron封装可行性研究 1. 引言&#xff1a;从WebUI到桌面应用的跨越 你有没有遇到过这种情况&#xff1a;手头有一张老照片&#xff0c;模糊、有噪点&#xff0c;甚至人脸都看不清。你想修复它&#xff0c;但专业的图像处理软件太复杂&a…

如何选择高性价比呼叫中心?2026年品牌推荐与排名,直击集成与扩展痛点

摘要 在数字化转型浪潮中,客户联络体验已成为企业核心竞争力的关键组成部分。传统呼叫中心正面临人力成本攀升、服务效率瓶颈与客户期望升级的多重压力,企业决策者亟需寻找能够实现降本增效、同时提供智能化、个性化…

C++ undefined reference 错误全解析,掌握这7种情况再也不怕编译失败

第一章&#xff1a;C undefined reference to 错误的本质与编译原理 C 中的 "undefined reference to" 错误是链接阶段最常见的错误之一&#xff0c;通常出现在编译器成功完成编译后&#xff0c;但在链接目标文件时无法找到函数或变量的定义。该错误并非语法问题&…

strcat函数安全隐患曝光:如何用安全版本避免缓冲区溢出?

第一章&#xff1a;strcat函数安全隐患曝光&#xff1a;缓冲区溢出的根源剖析 C语言中的 strcat 函数用于将一个字符串追加到另一个字符串的末尾&#xff0c;其原型定义在 string.h 头文件中&#xff1a; char *strcat(char *dest, const char *src); 该函数不检查目标缓冲区…

SenseVoiceSmall性能对比:多语言转录中GPU利用率提升方案评测

SenseVoiceSmall性能对比&#xff1a;多语言转录中GPU利用率提升方案评测 1. 引言&#xff1a;为什么我们需要更高效的语音理解模型&#xff1f; 在跨语言内容审核、智能客服、会议纪要生成等场景中&#xff0c;传统语音识别&#xff08;ASR&#xff09;只能输出“谁说了什么…

苏州牙齿种植优选:2026年口碑排行榜来袭,拔牙正畸/牙齿冠修复/牙齿正畸/正畸/牙齿黑洞修复,牙齿种植机构推荐排行榜

随着国民口腔健康意识的提升,牙齿种植已成为修复缺失牙的主流选择。然而,苏州地区口腔机构众多,技术实力、服务水平参差不齐,消费者如何筛选出真正优质的种植机构?本文基于公开市场数据、行业调研及消费者口碑,筛…

烧菜火锅哪家强?全网热议的五大品牌揭秘,美食/社区火锅/特色美食/火锅/烧菜火锅,烧菜火锅品牌排行

行业洞察:烧菜火锅为何成为新风口? 近年来,烧菜火锅凭借“现烧菜品+热辣锅底”的创新模式,在川渝火锅市场掀起热潮。与传统火锅相比,其核心优势在于将川菜烹饪技法融入火锅场景,通过现做烧菜(如红烧肉、耙蹄花)…

揭秘Boost并发库性能瓶颈:5个你必须知道的优化策略

第一章&#xff1a;揭秘Boost并发库性能瓶颈&#xff1a;5个你必须知道的优化策略 在高并发系统中&#xff0c;Boost.Asio 和 Boost.Thread 等组件常被用于实现异步任务调度与线程管理。然而&#xff0c;在高负载场景下&#xff0c;开发者常遭遇上下文切换开销大、锁竞争激烈以…

讲讲容器抛光加工哪家专业,无锡口碑好的品牌有哪些

一、基础认知篇 问题1:什么是不锈钢抛光加工?核心作用是什么? 不锈钢抛光加工是通过机械研磨、化学处理或电解作用,去除不锈钢表面氧化层、瑕疵与毛刺,提升光洁度、耐腐蚀性与装饰性的工艺过程。其核心作用体现在…

2025年活动板房厂家口碑排行,谁将登顶榜首?集装箱办公/集装箱销售/集装箱改造/网红集装箱/箱式房,活动板房批发排行

随着建筑行业对临时用房需求的持续攀升,活动板房因其灵活部署、成本可控、环保耐用等特性,成为工地、市政工程、商业服务的“刚需”。然而,市场分散、产品同质化严重、服务质量参差不齐等问题,导致企业采购时面临“…

无锡不锈钢抛光加工厂家口碑排名,前十名有谁?

一、基础认知篇 问题1:镜面不锈钢抛光加工的核心要求是什么?普通抛光和镜面抛光有本质区别吗? 镜面不锈钢抛光加工是通过多道精密研磨、抛光工序,使不锈钢表面粗糙度达到Ra0.01μm以下,形成类似镜面的高光泽、高反…

undefined reference to 到底怎么回事?3步快速定位并解决C++链接问题

第一章&#xff1a;undefined reference to 到底怎么回事&#xff1f; 当你在编译 C 或 C 程序时&#xff0c;遇到“undefined reference to”错误&#xff0c;通常意味着链接器无法找到某个函数或变量的定义。这并非编译阶段的问题&#xff0c;而是链接阶段的失败。编译器可以…

Qwen-Image-2512-ComfyUI企业应用案例:智能设计系统搭建

Qwen-Image-2512-ComfyUI企业应用案例&#xff1a;智能设计系统搭建 镜像/应用大全&#xff0c;欢迎访问 1. 引言&#xff1a;为什么企业需要智能设计系统&#xff1f; 在内容为王的时代&#xff0c;电商、广告、新媒体等行业对视觉素材的需求呈爆炸式增长。一个新品上线&am…

揭秘2026年十大葡萄籽品牌排行榜前十名,最好的品牌权威出炉

随着“内调外养”护肤理念的普及和健康抗衰需求的升级,葡萄籽作为天然强效抗氧化食材,已成为中老年人及爱美人群日常养护的核心选择。近日,2026年十大葡萄籽品牌权威榜单正式发布,引发市场广泛关注。其中,由专业科…

Live Avatar离线解码风险:长视频累积导致OOM问题说明

Live Avatar离线解码风险&#xff1a;长视频累积导致OOM问题说明 1. Live Avatar模型硬件需求与显存瓶颈 Live Avatar是由阿里联合高校开源的一款先进数字人生成模型&#xff0c;能够基于文本、图像和音频输入生成高质量的动态人物视频。该模型采用14B参数规模的DiT架构&…

视频文件上传时,JAVA如何实现分块与断点续传功能?

我&#xff0c;一个被大文件上传逼疯的大三狗&#xff0c;想和你唠唠毕业设计的血泪史 最近为了做毕业设计&#xff0c;我把头发薅掉了小半——老师要的是“能打”的文件管理系统&#xff0c;核心需求就一条&#xff1a;10G大文件上传&#xff0c;还要支持文件夹、断点续传、加…

二进制文件读写总出错?你可能没掌握这3种C语言正确姿势

第一章&#xff1a;二进制文件读写常见误区与本质剖析 在处理高性能数据存储或跨平台通信时&#xff0c;开发者常需直接操作二进制文件。然而&#xff0c;许多人在读写过程中忽视了字节序、数据对齐和编码假设等问题&#xff0c;导致程序在不同系统上行为不一致甚至崩溃。 误将…