01-18-04 AIDL接口定义语言
·
01-18-04 AIDL接口定义语言
AIDL是什么
AIDL(Android Interface Definition Language)是Android的接口定义语言,用于定义跨进程通信的接口。
核心作用:
- 定义客户端和服务端通信的接口
- 自动生成Binder代理代码
- 实现进程间通信(IPC)
为什么需要AIDL
跨进程通信场景
应用A进程 系统服务进程
↓ ↓
想获取应用列表 → PackageManagerService
↓ ↓
需要跨进程通信 ← 返回应用列表
问题:
- 不同进程内存隔离,无法直接调用
- 需要序列化数据传递
- 需要处理异步调用
解决方案:Binder + AIDL
AIDL基础语法
1. 定义AIDL接口
// IBookManager.aidl
package com.example.bookstore;
import com.example.bookstore.Book;
interface IBookManager {
// 获取书籍列表
List<Book> getBookList();
// 添加书籍
void addBook(in Book book);
// 删除书籍
void removeBook(in Book book);
// 根据ID查询
Book getBookById(int bookId);
// 注册监听器
void registerListener(IBookListener listener);
// 取消监听器
void unregisterListener(IBookListener listener);
}
2. 定义数据类型
// Book.aidl
package com.example.bookstore;
parcelable Book;
// Book.kt - 必须实现Parcelable
package com.example.bookstore
import android.os.Parcel
import android.os.Parcelable
data class Book(
val id: Int,
val name: String,
val author: String,
val price: Float
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString() ?: "",
parcel.readString() ?: "",
parcel.readFloat()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(id)
parcel.writeString(name)
parcel.writeString(author)
parcel.writeFloat(price)
}
override fun describeContents() = 0
companion object CREATOR : Parcelable.Creator<Book> {
override fun createFromParcel(parcel: Parcel) = Book(parcel)
override fun newArray(size: Int): Array<Book?> = arrayOfNulls(size)
}
}
3. 定义回调接口
// IBookListener.aidl
package com.example.bookstore;
import com.example.bookstore.Book;
interface IBookListener {
// 书籍添加通知
void onBookAdded(in Book book);
// 书籍删除通知
void onBookRemoved(in Book book);
}
AIDL生成的代码
自动生成的Stub类
// 编译后生成:IBookManager.java
public interface IBookManager extends android.os.IInterface {
// Stub类:服务端继承
public static abstract class Stub extends android.os.Binder
implements com.example.bookstore.IBookManager {
private static final java.lang.String DESCRIPTOR = "com.example.bookstore.IBookManager";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
// 将IBinder转换为接口
public static com.example.bookstore.IBookManager asInterface(android.os.IBinder obj) {
if (obj == null) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (iin != null && iin instanceof com.example.bookstore.IBookManager) {
// 同进程,直接返回
return (com.example.bookstore.IBookManager) iin;
}
// 跨进程,返回代理
return new com.example.bookstore.IBookManager.Stub.Proxy(obj);
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
throws android.os.RemoteException {
switch (code) {
case TRANSACTION_getBookList: {
data.enforceInterface(DESCRIPTOR);
// 调用实际实现
java.util.List<com.example.bookstore.Book> result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
com.example.bookstore.Book book;
if (data.readInt() != 0) {
book = com.example.bookstore.Book.CREATOR.createFromParcel(data);
} else {
book = null;
}
this.addBook(book);
reply.writeNoException();
return true;
}
// ... 其他方法
}
return super.onTransact(code, data, reply, flags);
}
// Proxy类:客户端使用
private static class Proxy implements com.example.bookstore.IBookManager {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public java.util.List<com.example.bookstore.Book> getBookList()
throws android.os.RemoteException {
android.os.Parcel data = android.os.Parcel.obtain();
android.os.Parcel reply = android.os.Parcel.obtain();
java.util.List<com.example.bookstore.Book> result;
try {
data.writeInterfaceToken(DESCRIPTOR);
// 发起跨进程调用
mRemote.transact(Stub.TRANSACTION_getBookList, data, reply, 0);
reply.readException();
result = reply.createTypedArrayList(com.example.bookstore.Book.CREATOR);
} finally {
reply.recycle();
data.recycle();
}
return result;
}
@Override
public void addBook(com.example.bookstore.Book book)
throws android.os.RemoteException {
android.os.Parcel data = android.os.Parcel.obtain();
android.os.Parcel reply = android.os.Parcel.obtain();
try {
data.writeInterfaceToken(DESCRIPTOR);
if (book != null) {
data.writeInt(1);
book.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, data, reply, 0);
reply.readException();
} finally {
reply.recycle();
data.recycle();
}
}
// ... 其他方法
}
// 方法ID常量
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
// ...
}
// 接口方法声明
public java.util.List<com.example.bookstore.Book> getBookList() throws android.os.RemoteException;
public void addBook(com.example.bookstore.Book book) throws android.os.RemoteException;
// ...
}
服务端实现
1. 实现AIDL接口
class BookManagerService : Service() {
// 书籍列表(线程安全)
private val bookList = CopyOnWriteArrayList<Book>()
// 监听器列表
private val listenerList = RemoteCallbackList<IBookListener>()
// Binder对象
private val binder = object : IBookManager.Stub() {
override fun getBookList(): List<Book> {
// 可能被多个客户端同时调用,注意线程安全
return ArrayList(bookList)
}
override fun addBook(book: Book?) {
book ?: return
synchronized(bookList) {
// 检查是否已存在
if (bookList.any { it.id == book.id }) {
return
}
bookList.add(book)
// 通知所有监听器
notifyBookAdded(book)
}
}
override fun removeBook(book: Book?) {
book ?: return
synchronized(bookList) {
bookList.removeAll { it.id == book.id }
// 通知所有监听器
notifyBookRemoved(book)
}
}
override fun getBookById(bookId: Int): Book? {
return bookList.find { it.id == bookId }
}
override fun registerListener(listener: IBookListener?) {
listener ?: return
listenerList.register(listener)
}
override fun unregisterListener(listener: IBookListener?) {
listener ?: return
listenerList.unregister(listener)
}
}
override fun onBind(intent: Intent?): IBinder {
return binder
}
/**
* 通知所有监听器:书籍已添加
*/
private fun notifyBookAdded(book: Book) {
val count = listenerList.beginBroadcast()
for (i in 0 until count) {
try {
listenerList.getBroadcastItem(i).onBookAdded(book)
} catch (e: RemoteException) {
e.printStackTrace()
}
}
listenerList.finishBroadcast()
}
/**
* 通知所有监听器:书籍已删除
*/
private fun notifyBookRemoved(book: Book) {
val count = listenerList.beginBroadcast()
for (i in 0 until count) {
try {
listenerList.getBroadcastItem(i).onBookRemoved(book)
} catch (e: RemoteException) {
e.printStackTrace()
}
}
listenerList.finishBroadcast()
}
}
2. 注册Service
<!-- AndroidManifest.xml -->
<service
android:name=".BookManagerService"
android:process=":remote"
android:exported="true">
<intent-filter>
<action android:name="com.example.bookstore.IBookManager"/>
</intent-filter>
</service>
客户端调用
1. 绑定Service
class MainActivity : AppCompatActivity() {
private var bookManager: IBookManager? = null
private var isBound = false
// ServiceConnection
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
// 获取服务接口
bookManager = IBookManager.Stub.asInterface(service)
isBound = true
// 注册监听器
registerListener()
// 使用服务
loadBooks()
}
override fun onServiceDisconnected(name: ComponentName?) {
bookManager = null
isBound = false
}
}
// 监听器实现
private val listener = object : IBookListener.Stub() {
override fun onBookAdded(book: Book?) {
book ?: return
// 在Binder线程调用,需要切换到主线程
runOnUiThread {
Toast.makeText(this@MainActivity, "新书:${book.name}", Toast.LENGTH_SHORT).show()
loadBooks()
}
}
override fun onBookRemoved(book: Book?) {
book ?: return
runOnUiThread {
Toast.makeText(this@MainActivity, "删除:${book.name}", Toast.LENGTH_SHORT).show()
loadBooks()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 绑定服务
bindBookService()
}
private fun bindBookService() {
val intent = Intent().apply {
action = "com.example.bookstore.IBookManager"
setPackage(packageName) // Android 5.0+需要显式指定包名
}
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
private fun registerListener() {
try {
bookManager?.registerListener(listener)
} catch (e: RemoteException) {
e.printStackTrace()
}
}
private fun loadBooks() {
try {
val books = bookManager?.getBookList()
// 更新UI
updateBookList(books)
} catch (e: RemoteException) {
e.printStackTrace()
}
}
fun onAddBookClick(view: View) {
val book = Book(
id = System.currentTimeMillis().toInt(),
name = "Android开发艺术探索",
author = "任玉刚",
price = 79f
)
try {
bookManager?.addBook(book)
} catch (e: RemoteException) {
e.printStackTrace()
}
}
override fun onDestroy() {
super.onDestroy()
// 取消监听器
if (isBound) {
try {
bookManager?.unregisterListener(listener)
} catch (e: RemoteException) {
e.printStackTrace()
}
unbindService(connection)
}
}
private fun updateBookList(books: List<Book>?) {
// 更新RecyclerView
}
}
AIDL参数定向标记
in、out、inout的区别
interface IDataManager {
// in:数据从客户端流向服务端(默认)
void setData(in Data data);
// out:数据从服务端流向客户端
void getData(out Data data);
// inout:双向传递
void processData(inout Data data);
}
性能影响:
- in:只序列化一次(客户端→服务端)
- out:只序列化一次(服务端→客户端)
- inout:序列化两次(往返)
最佳实践:
// [通过] 使用in(默认)
void addBook(in Book book);
// [未通过] 不必要的inout
// void addBook(inout Book book);
AIDL支持的数据类型
1. 基本类型
interface IDataManager {
void setInt(int value);
void setLong(long value);
void setFloat(float value);
void setDouble(double value);
void setBoolean(boolean value);
void setString(String value);
}
2. 集合类型
interface IDataManager {
List<String> getStringList();
Map<String, String> getStringMap();
}
3. Parcelable对象
// 需要单独的.aidl文件声明
parcelable Book;
4. 其他AIDL接口
interface IBookManager {
void registerListener(IBookListener listener);
}
常见问题
问题1:RemoteException处理
// [未通过] 忘记处理RemoteException
fun getBooks() {
val books = bookManager?.getBookList() // 可能抛RemoteException
}
// [通过] 正确处理
fun getBooks() {
try {
val books = bookManager?.getBookList()
// 处理数据
} catch (e: RemoteException) {
e.printStackTrace()
// 处理异常:可能服务已崩溃
}
}
问题2:Binder线程切换
// [未通过] 在Binder线程更新UI
private val listener = object : IBookListener.Stub() {
override fun onBookAdded(book: Book?) {
// 在Binder线程,不能直接更新UI
textView.text = book?.name // 崩溃!
}
}
// [通过] 切换到主线程
private val listener = object : IBookListener.Stub() {
override fun onBookAdded(book: Book?) {
book ?: return
runOnUiThread {
textView.text = book.name
}
}
}
问题3:监听器泄漏
// [通过] 取消监听器
override fun onDestroy() {
super.onDestroy()
try {
bookManager?.unregisterListener(listener)
} catch (e: RemoteException) {
e.printStackTrace()
}
unbindService(connection)
}
问题4:权限控制
// 服务端检查权限
private val binder = object : IBookManager.Stub() {
override fun addBook(book: Book?) {
// 检查调用者权限
if (checkCallingPermission("com.example.BOOK_PERMISSION") !=
PackageManager.PERMISSION_GRANTED) {
throw SecurityException("No permission")
}
// 业务逻辑
bookList.add(book)
}
}
总结
AIDL核心概念
- AIDL接口:定义跨进程通信的契约
- Stub类:服务端实现,处理请求
- Proxy类:客户端代理,发起请求
- Binder:底层IPC机制
使用流程
- 定义AIDL接口
- 实现Stub(服务端)
- 绑定Service获取代理(客户端)
- 调用接口方法
- 处理RemoteException
最佳实践
- 使用in参数(默认)
- 处理RemoteException
- Binder线程切换到主线程
- 取消监听器避免泄漏
- 服务端检查权限
Android 16 (API 36) AIDL变化
稳定AIDL语言进一步推广
更多系统服务迁移到稳定AIDL
// Android 16:更多系统服务使用稳定AIDL定义
// 取代传统非稳定AIDL接口
@VintfStability
interface IActivityTaskManager {
// 稳定接口,保证长期兼容性
int startActivity(in Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode,
int startFlags, in ProfilerInfo profilerInfo, in Bundle options);
}
AIDL生成的代码优化
Kotlin AIDL支持增强
// Android 16:AIDL 对 Kotlin 的默认参数支持更好
// 生成的 Stub 代码更加 Kotlin 友好
interface IBookManager {
// 支持 default 参数值
void addBook(in Book book, boolean notifyListener = true);
}
性能优化
Android 16 的 Binder 事务处理优化:
- 减少跨进程调用的序列化开销
- 优化的 Parcel 读写性能
- 更好的 Binder 线程池调度
- 支持更大的事务缓冲区
关键要点:AIDL是Android跨进程通信的标准方案,理解其生成的代码有助于掌握Binder机制
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)