AIDL 深入解析
2026/8/23大约 4 分钟
🔗 AIDL 深入解析
面试高频指数:⭐⭐⭐⭐ AIDL 是 Binder 机制的应用层封装,理解 Stub/Proxy 结构才算真正掌握 IPC。
1. AIDL 是什么
AIDL(Android Interface Definition Language)
Android 接口定义语言,用于跨进程通信的接口定义
本质:定义 IPC 接口的语法糖,编译器生成 Binder 通信代码
适用:多进程、跨应用通信(音乐播放、系统服务调用)2. AIDL 文件语法
// IBookManager.aidl
package com.example.aidl;
// 自定义类型需显式 import
import com.example.aidl.Book;
interface IBookManager {
// 基本类型直接使用
List<Book> getBookList();
// 定向 tag:in / out / inout
// in :客户端 → 服务端(默认,数据单向传入)
// out :服务端 → 客户端(服务端修改后回传)
// inout:双向
void addBook(in Book book);
void updateBook(inout Book book);
// oneway:异步调用(不阻塞客户端,单向)
oneway void notifyChanged();
}// 自定义 Parcelable 类型 Book.aidl
package com.example.aidl;
parcelable Book;
// Book.java 实现 Parcelable 接口3. 服务端实现
class BookManagerService : Service() {
private val bookList = mutableListOf<Book>()
// 内部类继承 Stub,实现接口方法
private val binder = object : IBookManager.Stub() {
override fun getBookList(): List<Book> {
return bookList
}
override fun addBook(book: Book) {
bookList.add(book)
}
override fun updateBook(book: Book) {
// inout 参数:修改会回传给客户端
book.price = 999
}
override fun notifyChanged() {
// oneway:异步执行
}
}
override fun onBind(intent: Intent): IBinder = binder
}4. 客户端使用
class MainActivity : AppCompatActivity() {
private var bookManager: IBookManager? = null
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
// 通过 asInterface 获取代理对象
bookManager = IBookManager.Stub.asInterface(service)
}
override fun onServiceDisconnected(name: ComponentName?) {
bookManager = null
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intent = Intent(this, BookManagerService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
fun addBook() {
bookManager?.addBook(Book("Android 进阶", 99))
}
override fun onDestroy() {
super.onDestroy()
unbindService(connection)
}
}5. Stub 与 Proxy 原理
// AIDL 编译器生成的代码结构
public interface IBookManager extends IInterface {
// Stub:服务端基类(Binder 实体)
public static abstract class Stub extends Binder implements IBookManager {
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
// 客户端获取代理:在本进程直接返回 this,跨进程返回 Proxy
public static IBookManager asInterface(IBinder obj) {
if (obj == null) return null;
IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (iin != null && iin instanceof IBookManager) {
return (IBookManager) iin; // 同进程:直接返回
}
return new Proxy(obj); // 跨进程:返回代理
}
// 服务端:Binder.onTransact 分发请求
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
switch (code) {
case TRANSACTION_addBook:
data.enforceInterface(DESCRIPTOR);
Book book = Book.CREATOR.createFromParcel(data);
this.addBook(book);
reply.writeNoException();
return true;
}
}
}
// Proxy:客户端代理(包装 Binder 驱动调用)
private static class Proxy implements IBookManager {
private IBinder mRemote;
@Override
public void addBook(Book book) {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(DESCRIPTOR);
book.writeToParcel(data, 0); // 序列化参数
mRemote.transact(TRANSACTION_addBook, data, reply, 0); // 跨进程调用
reply.readException();
} finally {
data.recycle();
reply.recycle();
}
}
}
}核心流程:
客户端 Proxy.addBook()
→ data 写入参数(Parcel 序列化)
→ mRemote.transact()(Binder 驱动,进入内核)
→ 服务端 Stub.onTransact()
→ 反序列化参数 → 调用真实方法
→ 结果写入 reply → 回传客户端6. 线程模型
① 客户端调用默认阻塞(同步),在调用线程执行
② 服务端方法执行在 Binder 线程池(非主线程)!
③ 服务端需手动切换主线程更新 UI(Handler/runOnUiThread)
④ oneway 修饰的方法:客户端不等待返回(异步)
⑤ 跨进程回调:用 RemoteCallbackList 管理(自动处理死亡)// 服务端跨进程回调
private val callbacks = RemoteCallbackList<IOnNewBookArrivedListener>()
fun register(listener: IOnNewBookArrivedListener) {
callbacks.register(listener)
}
// 通知所有客户端(Binder 线程池中执行)
fun notifyNewBook(book: Book) {
val count = callbacks.beginBroadcast()
for (i in 0 until count) {
callbacks.getBroadcastItem(i)?.onNewBookArrived(book)
}
callbacks.finishBroadcast()
}7. 高频面试题
Q1:AIDL 中 in/out/inout 的区别? A:in 单向传入(服务端修改不回传,性能最好);out 单向传出(参数初始值 不传入,服务端赋值后回传);inout 双向(传+回,序列化两次,性能最差)。 对象类型建议用 in,减少开销。
Q2:AIDL 与 Messenger 怎么选? A:AIDL 适合复杂接口、多方法、双向通信;Messenger 基于 Handler 封装 (串行、只传 Message),适合简单消息传递。追求性能与灵活用 AIDL。
Q3:服务端方法执行在哪个线程? A:Binder 线程池(BinderThread),非主线程。所以服务端方法里操作 UI 必须 切回主线程。客户端默认同步阻塞,耗时操作放子线程。
Q4:oneway 的作用? A:异步调用,客户端发出后立即返回(不等待回复),用于通知类接口。 限制:不能有返回值、不能有 out/inout 参数。底层 Binder 驱动直接返回。
Q5:AIDL 回调导致内存泄漏怎么处理? A:客户端死亡时服务端需清理(linkToDeath 监听);用 RemoteCallbackList 管理跨进程回调(自动处理 binderDied 与死循环遍历)。
8. 小结
- AIDL = 接口定义 + 编译器生成 Stub/Proxy。
- 定向 tag:in(传)、out(回)、inout(双向)。
- 服务端在 Binder 线程池执行,客户端同步阻塞。
- oneway 异步通知、RemoteCallbackList 管理回调。
- 面试重点:Stub/Proxy 结构、transact/onTransact、线程模型。