跳到主要内容

AIDL

问题

AIDL 是什么?Stub 和 Proxy 分别做什么?

答案

AIDL 是什么

AIDL(Android Interface Definition Language)是 Android 定义跨进程接口的 IDL 语言,编译器会自动生成 Binder 通信的模板代码(Stub + Proxy)。

使用流程

Step 1: 定义 AIDL 接口

IBookManager.aidl
package com.example;

import com.example.Book;

interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
// oneway 异步调用
oneway void notifyUpdate();
}
Book.aidl
package com.example;
parcelable Book;

Step 2: Server 端实现 Stub

class BookService : Service() {
private val books = mutableListOf<Book>()

private val binder = object : IBookManager.Stub() {
override fun getBookList(): List<Book> = books

override fun addBook(book: Book) {
books.add(book)
}

override fun notifyUpdate() {
// 异步执行,不阻塞 Client
}
}

override fun onBind(intent: Intent): IBinder = binder
}

Step 3: Client 端绑定获取 Proxy

class BookActivity : AppCompatActivity() {
private var bookManager: IBookManager? = null

private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
// IBinder → Proxy(跨进程)或直接引用(同进程)
bookManager = IBookManager.Stub.asInterface(service)
}

override fun onServiceDisconnected(name: ComponentName) {
bookManager = null
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intent = Intent(this, BookService::class.java)
bindService(intent, connection, BIND_AUTO_CREATE)
}

private fun loadBooks() {
// 注意:跨进程 AIDL 调用在 Binder 线程执行,应在子线程调用
lifecycleScope.launch(Dispatchers.IO) {
val books = bookManager?.bookList
}
}
}

Stub 和 Proxy 的关系

角色位置作用
StubServer 进程接收请求,解包参数,调用实际实现
ProxyClient 进程打包参数为 Parcel,通过 Binder 驱动发送

IBookManager.Stub.asInterface(binder)

  • 同进程:直接返回 Stub 本身(无需 IPC)
  • 跨进程:返回 Proxy 包装类

AIDL 回调(双向通信)

ICallback.aidl
interface ICallback {
void onBookAdded(in Book book);
}
// Server 端维护回调列表
private val callbacks = RemoteCallbackList<ICallback>()

override fun registerCallback(callback: ICallback) {
callbacks.register(callback)
}

// 通知所有客户端
private fun notifyClients(book: Book) {
val count = callbacks.beginBroadcast()
for (i in 0 until count) {
callbacks.getBroadcastItem(i).onBookAdded(book)
}
callbacks.finishBroadcast()
}
RemoteCallbackList

不要用普通 List 管理远程回调。跨进程传输的 Binder 对象每次反序列化都是新对象,remove() 无法匹配。RemoteCallbackList 内部通过 Binder 的唯一标识来管理,并能自动处理进程死亡回调的解注册。


常见面试问题

Q1: in/out/inout 标记分别是什么意思?

答案

  • in:数据只从 Client 传到 Server(最常用,性能最好)
  • out:Server 修改的数据回传 Client(参数在 Server 端是空的,执行后回写)
  • inout:双向传递,性能开销最大

默认基本类型和 String 是 in。Parcelable 对象需要显式标注。

Q2: AIDL 方法在哪个线程执行?

答案

  • Server 端:AIDL 方法在 Binder 线程池中执行(非主线程),需要注意线程同步
  • Client 端:同步调用会阻塞当前线程,应避免在主线程调用耗时 AIDL 方法
  • oneway:Client 调用后立即返回,Server 端仍在 Binder 线程池中串行执行

相关链接