AIDL 全稱 Android Interface Definition Language,即 Android 接口描述語言。雖然名稱聽起來很專業,但其本質只是一個生成進程間通信(IPC)接口的輔助工具。它以 .aidl 文件形式存在,開發者只需在其中定義進程間通信的接口,編譯時 IDE 會自動根據接口文件生成可供項目使用的 .java 文件,這類似於我們常說的「語法糖」。
AIDL 的語法與 Java 基本一致,唯一的細微差別在於導包機制。在 Java 中,同一包下的類無需導包,但在 AIDL 中必須顯式聲明導包。
我們以一個圖書管理系統為例,採用 C/S 架構:具體管理功能由服務端進程實現,客戶端僅需調用相應接口。
在項目中創建 aidl 包,包含三個文件:Book.java、Book.aidl、IBookManager.aidl。
// Book.java - 實體類,實現 Parcelable 接口以支持進程間傳輸
package com.example.aidl;
public class Book implements Parcelable {
int bookId;
String bookName;
public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
// ... Parcelable 相關方法實現
}
// Book.aidl - 實體類在 AIDL 中的聲明 package com.example.aidl; parcelable Book;
// IBookManager.aidl - 服務端與客戶端通信接口
package com.example.aidl;
import com.example.aidl.Book;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
}
關鍵點說明:
Book.java:實體類,實現 Parcelable 接口才能在進程間傳輸Book.aidl:實體類在 AIDL 中的聲明文件IBookManager:通信接口,注意參數前需加方向標識:in(輸入)、out(輸出)、inout(輸入輸出)編譯後,Android Studio 會自動生成一個包含三個靜態內部類的 .java 文件:
public interface IBookManager extends android.os.IInterface {
public void addBook(net.bingyan.library.Book book) throws android.os.RemoteException;
public java.util.List<net.bingyan.library.Book> getBookList() throws android.os.RemoteException;
}
public static abstract class Stub extends android.os.Binder implements net.bingyan.library.IBookManager {
private static final java.lang.String DESCRIPTOR = "net.bingyan.library.IBookManager";
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
public Stub() { this.attachInterface(this, DESCRIPTOR); }
public static net.bingyan.library.IBookManager asInterface(android.os.IBinder obj) { ... }
@Override public android.os.IBinder asBinder() { return this; }
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
throws android.os.RemoteException { ... }
}
private static class Proxy implements net.bingyan.library.IBookManager {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) { mRemote = remote; }
@Override public android.os.IBinder asBinder() { return mRemote; }
public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; }
@Override public void addBook(net.bingyan.library.Book book) throws android.os.RemoteException { ... }
@Override public java.util.List<net.bingyan.library.Book> getBookList() throws android.os.RemoteException { ... }
}
android.os.IInterface,作為服務端與客戶端通信的「窗口」Binder 並實現 IBookManager,用於服務端,需由服務端實現具體業務邏輯IBookManager,封裝了底層 Binder 通信機制,客戶端通過它進行遠程方法調用Proxy 的構造方法接收 IBinder 類型參數 remote,代表服務端。以 addBook() 為例:
@Override
public void addBook(net.bingyan.library.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();
}
}
核心機制:
Parcel 對象:_data 發送請求數據,_reply 接收響應數據mRemote.transact() 發起遠程方法調用(RPC),這是一個耗時操作writeToParcel(),反序列化通過 CREATOR.createFromParcel()Parcel 打包/解包順序必須嚴格對應
public static net.bingyan.library.IBookManager asInterface(android.os.IBinder obj) {
if (obj == null) return null;
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (iin != null && iin instanceof net.bingyan.library.IBookManager) {
return (net.bingyan.library.IBookManager) iin;
}
return new net.bingyan.library.IBookManager.Stub.Proxy(obj);
}
作用:將 Stub 轉換為 IBookManager 接口。同進程直接轉型,跨進程返回 Proxy 代理。
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: { ... }
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
Book _arg0 = (0 != data.readInt()) ? Book.CREATOR.createFromParcel(data) : null;
this.addBook(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getBookList: { ... }
}
return super.onTransact(code, data, reply, flags);
}
關鍵點:
transact() 是遠程調用發起,onTransact() 是響應處理code 標識調用哪個方法(TRANSACTION_addBook、TRANSACTION_getBookList)
public class BookManagerService extends Service {
private final List<Book> mLibrary = new ArrayList<>();
private IBookManager mBookManager = new IBookManager.Stub() {
@Override
public void addBook(Book book) throws RemoteException {
synchronized (mLibrary) {
mLibrary.add(book);
Log.d("BookManagerService", "now our library has " + mLibrary.size() + " books");
}
}
@Override
public List<Book> getBookList() throws RemoteException {
return mLibrary;
}
};
@Override
public IBinder onBind(Intent intent) {
return mBookManager.asBinder();
}
}
在 Manifest 中註冊並指定獨立進程:
<service android:process=":remote" android:name=".BookManagerService"/>
public class Client extends AppCompatActivity {
private TextView textView;
private IBookManager bookManager;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.library_book_manager_system_client);
Intent i = new Intent(Client.this, BookManagerService.class);
bindService(i, conn, BIND_AUTO_CREATE);
Button addABook = findViewById(R.id.button);
addABook.setOnClickListener(v -> {
if (bookManager == null) return;
try {
bookManager.addBook(new Book(0, "book"));
textView.setText(getString(R.string.book_management_system_book_count,
String.valueOf(bookManager.getBookList().size())));
} catch (RemoteException e) {
e.printStackTrace();
}
});
textView = findViewById(R.id.textView);
}
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = IBookManager.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("Client", name.toString());
}
};
}

每次點擊按鈕,客戶端通過 AIDL 成功向服務端添加一本書,驗證了跨進程通信功能正常。