本文參考《Android開發(fā)藝術(shù)探索》,建議照著代碼看文章。GitHub-完整代碼鏈接
AIDL 支持下列數(shù)據(jù)類型:
- Java 編程語言中的所有原語類型:byte、short 、int、long、float、double、char、boolean。
- List:只支持ArrayList,List的每個元素也需要是AIDL支持的數(shù)據(jù)類型。
- Map: 值支持HashMap,Map的key和value也需要是AIDL支持的數(shù)據(jù)類型。
- Parcelable:實現(xiàn)了Parcelable接口的對象。
- AIDL:所有的AIDL接口本身也可以在AIDL文件中使用。
Binder的跨進(jìn)程工作機制

通過Binder實現(xiàn)跨進(jìn)程通信,提供服務(wù)的進(jìn)程被稱為服務(wù)端,請求服務(wù)的進(jìn)程是客戶端。
服務(wù)端:服務(wù)端首先要創(chuàng)建一個AIDL文件,將暴露給客戶端的方法在這個AIDL文件中聲明,接著創(chuàng)建一個Binder類繼承AIDL接口中的Stub類,并實現(xiàn)Stub中的抽象方法。然后創(chuàng)建一個Service用來監(jiān)聽客戶端的連接請求,在Service的onBind方法中返回這個Binder類的對象。
客戶端:客戶端首先要綁定服務(wù)端的Service,綁定成功后,將服務(wù)端返回的Binder對象轉(zhuǎn)成AIDL接口所屬的類型,接著就可以調(diào)用AIDL中的方法了。
不知道上面的文字在說什么,沒關(guān)系,下面看個例子。這個例子實現(xiàn)跨進(jìn)程獲取書籍列表和添加書籍的功能。
獲取書籍列表調(diào)用過程如下圖所示,可以先大致瀏覽一下。

我們先從服務(wù)端開始
定義一個Book類實現(xiàn)Parcelable接口,實現(xiàn)Parcelable接口是為了能夠?qū)崿F(xiàn)跨進(jìn)程傳輸。
public class Book implements Parcelable {
private int bookId;
private String bookName;
public Book() {
}
public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
protected Book(Parcel in) {
bookId = in.readInt();
bookName = in.readString();
}
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(bookId);
dest.writeString(bookName);
}
/**
* 參數(shù)是一個Parcel,用它來存儲與傳輸數(shù)據(jù)
* @param dest
*/
public void readFromParcel(Parcel dest) {
//注意,此處的讀值順序應(yīng)當(dāng)是和writeToParcel()方法中一致的
bookId = dest.readInt();
bookName = dest.readString();
}
@Override
public String toString() {
return "{bookId:" + bookId + ",bookName:" + bookName + "}";
}
//省略getter/setter
}
如果一個AIDL文件中用到了自定義的Parcelable對象類,那么必須新建一個和它同名的AIDL文件,并在其中聲明它為parcelable類型。
為Book類聲明對應(yīng)的AIDL文件Book.aidl
// Book.aidl
package com.hm.aidlserver;
parcelable Book;
定義一個AIDL文件IBookManager.aidl,在其中聲明獲取書籍列表和添加書籍的方法。
// IBookManager.aidl
package com.hm.aidlserver;
//顯式引入Book類
import com.hm.aidlserver.Book;
interface IBookManager {
List<Book>getBookList();
void addBook(in Book book);
}
注意:自定義的Parcelable對象類和AIDL文件必須要顯式的import進(jìn)來,不管它們是否和當(dāng)前的AIDL文件位于同一個包內(nèi)。
聲明完了AIDL文件,重新build項目即可在build目錄下看到系統(tǒng)為我們生成的用于進(jìn)程間通信的類
../build/generated/source/aidl/debug/com/hm/aidlserver/IBookManager.java
我將該類調(diào)整了一下格式方便查看
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: /Users/dumingwei/AndroidStudioProjects/AIDLDemo/aidlserver/src/main/aidl/com/hm/aidlserver/IBookManager.aidl
*/
package com.hm.aidlserver;
public interface IBookManager extends android.os.IInterface {
//抽象方法,獲取書籍列表
public java.util.List<com.hm.aidlserver.Book> getBookList() throws android.os.RemoteException;
//抽象方法,添加書籍
public void addBook(com.hm.aidlserver.Book book) throws android.os.RemoteException;
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.hm.aidlserver.IBookManager {
private static final java.lang.String DESCRIPTOR = "com.hm.aidlserver.IBookManager";
//標(biāo)志獲取書籍列表的方法
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
//標(biāo)志添加書籍的方法
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.hm.aidlserver.IBookManager interface,
* generating a proxy if needed.
*/
public static com.hm.aidlserver.IBookManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
//客戶端調(diào)用queryLocalInterface(String descriptor)方法,返回的肯定是null
//服務(wù)端調(diào)用queryLocalInterface(String descriptor)方法,返回的不是null
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.hm.aidlserver.IBookManager))) {
return ((com.hm.aidlserver.IBookManager) iin);
}
//客戶端最終返回的是一個代理對象
return new com.hm.aidlserver.IBookManager.Stub.Proxy(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 {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_getBookList: {
data.enforceInterface(descriptor);
java.util.List<com.hm.aidlserver.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(descriptor);
com.hm.aidlserver.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.hm.aidlserver.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
//這個類是給客戶端用的
private static class Proxy implements com.hm.aidlserver.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 java.util.List<com.hm.aidlserver.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.hm.aidlserver.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.hm.aidlserver.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addBook(com.hm.aidlserver.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();
}
}
}
}
}
各個類的職責(zé)
IBinder :IBinder 是一個接口,代表了一種跨進(jìn)程通信的能力。只要實現(xiàn)了這個接口,這個對象就能跨進(jìn)程傳輸。IBinder的直接子類是
Binder和BinderProxy。這兩個類都繼承自 IBinder, 因而都具有跨進(jìn)程傳輸?shù)哪芰?;Binder代表的是服務(wù)端Binder本地對象。BinderProxy類,它是服務(wù)端的Binder對象的代理對象;實際上,在跨越進(jìn)程的時候,Binder驅(qū)動會自動完成這兩個對象的轉(zhuǎn)換,客戶端真正拿到的是服務(wù)端的Binder對象的代理對象(即一個BinderProxy類型的對象)。IInterface :IInterface 代表的就是 Server 進(jìn)程對象具備什么樣的能力(能提供哪些方法,其實對應(yīng)的就是 AIDL 文件中定義的接口)。
Stub :編譯工具會給我們定義的AIDL 文件生成一個名為 Stub 的靜態(tài)內(nèi)部類;這個類繼承了Binder, 說明它是一個Binder本地對象,它實現(xiàn)了IInterface接口,表明它具有 Server承諾給Client 的能力。Stub是一個抽象類,具體的IInterface的相關(guān)實現(xiàn)需要開發(fā)者自己實現(xiàn)。
Stub.Proxy:服務(wù)端Binder對象(這個Binder對象就是我們在Service中定義的具體的Binder對象,該對象可以跨進(jìn)程通信, 并且是實現(xiàn)了IBookManager接口)的代理類,客戶端是通過BinderProxy對象獲取到服務(wù)端Binder對象的代理類Proxy,然后通過這個代理類調(diào)用服務(wù)端的方法。
自動生成的IBookManager.java中,聲明了我們在AIDL文件中定義的方法
//抽象方法,獲取書籍列表
public java.util.List<com.hm.aidlserver.Book> getBookList() throws android.os.RemoteException;
//抽象方法添加書籍
public void addBook(com.hm.aidlserver.Book book) throws android.os.RemoteException;
在IBookManager.java文件中,還為我們生成了一個抽象的內(nèi)部類Stub。
public static abstract class Stub extends android.os.Binder implements com.hm.aidlserver.IBookManager {
//用來標(biāo)志Binder對象的名字
private static final java.lang.String DESCRIPTOR = "com.hm.aidlserver.IBookManager";
//標(biāo)志獲取書籍列表的方法
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
//標(biāo)志添加書籍的方法
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
//...
}
注意:Stub抽象類繼承了android.os.Binder類并實現(xiàn)了com.hm.aidlserver.IBookManager接口,但是并沒有實現(xiàn)com.hm.aidlserver.IBookManager接口中的抽象方法。我們最后在服務(wù)端返回的Binder對象要繼承Stub類并實現(xiàn)com.hm.aidlserver.IBookManager接口中的抽象方法。
在Stub類中,還為我們生成了一個私有的靜態(tài)內(nèi)部類Proxy,客戶端就是使用這個代理類來實現(xiàn)和服務(wù)端進(jìn)行通信的,后面再細(xì)說。
private static class Proxy implements com.hm.aidlserver.IBookManager {
//...
}
服務(wù)端Service的實現(xiàn)
/**
* 服務(wù)端的Service
*/
public class BookManagerService extends Service {
private static final String TAG = BookManagerService.class.getSimpleName();
//使用CopyOnWriteArrayList,因為可能會有多個客戶端同時操作書籍列表造成線程同步的問題
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
public BookManagerService() {
}
/**
* 實現(xiàn)IBookManager接口中的方法
*/
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
}
@Override
public void onCreate() {
super.onCreate();
//創(chuàng)建Service的時候先主動添加兩個書籍
mBookList.add(new Book(1, "Android"));
mBookList.add(new Book(2, "ios"));
}
@Override
public IBinder onBind(Intent intent) {
//返回binder對象
return mBinder;
}
}
在BookManagerService中我們創(chuàng)建了一個Binder對象mBinder,mBinder實現(xiàn)IBookManager.aidl中定義的方法。然后我們在onBind方法中返回mBinder對象即可。
我們的書籍列表類型使用了CopyOnWriteArrayList,因為可能會有多個客戶端同時操作書籍列表造成線程同步的問題。
注意:不要忘了在AndroidManifest.xml文件中注冊BookManagerService
<service
android:name=".BookManagerService"
android:enabled="true"
android:exported="true">
</service>
到這,一個簡單的服務(wù)端就實現(xiàn)了,接下來我們實現(xiàn)客戶端。
客戶端的實現(xiàn)
首先把在服務(wù)端定義的類和AIDL文件都拷貝到客戶端(具體的項目結(jié)構(gòu)可以下載源碼看一看),重新build項目即可在build目錄下看到系統(tǒng)為我們生成的用于進(jìn)程間通信的類。
綁定遠(yuǎn)程服務(wù)
//定義IBookManager對象
private IBookManager bookManager;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//注釋1處,注意這個的service對象是一個BinderProxy對象
Log.e(TAG, "onServiceConnected:" + service.getClass().getCanonicalName());
//注釋2處,獲取bookManager對象,注意這個傳入的service對象是一個BinderProxy對象
bookManager = IBookManager.Stub.asInterface(service);
Log.e(TAG, "onServiceConnected:" + bookManager.getClass().getCanonicalName());
try {
getBookList();
bookManager.registerListener(mOnNewBookArriveListener);
} catch (RemoteException e) {
e.printStackTrace();
Log.e(TAG, "onServiceConnected: error" + e.getMessage());
}
}
//...
};
綁定服務(wù)
private void bind() {
binded = true;
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.hm.aidlserver", "com.hm.aidlserver.BookManagerService"));
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
綁定遠(yuǎn)程服務(wù)以后,我們就可以調(diào)用服務(wù)端的方法了
獲取書籍列表
public void getBookList() {
if (bookManager != null) {
new Thread(new Runnable() {
@Override
public void run() {
try {
//獲取書籍列表
bookList = bookManager.getBookList();
Log.e(TAG, "query book list,list type:" + bookList.getClass().getCanonicalName());
Log.e(TAG, "query book list,list:" + bookList.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}).start();
}
}
添加書籍
public void addBook() {
if (bookManager != null) {
new Thread(new Runnable() {
@Override
public void run() {
try {
//添加書籍
bookManager.addBook(new Book(bookId, "Android 進(jìn)階" + bookId));
bookId++;
//添加完畢后,重新獲取一下書籍列表
bookList = bookManager.getBookList();
Log.e(TAG, "query book list,list type:" + bookList.getClass().getCanonicalName());
Log.e(TAG, "query book list,list:" + bookList.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}).start();
}
}
注意:當(dāng)客戶端調(diào)用服務(wù)端的方法時,如果是耗時方法的話,我們不能在主線程調(diào)用,否則可能會導(dǎo)致ANR,所以我們開啟新線程來調(diào)用服務(wù)端的方法。
現(xiàn)在我們已經(jīng)可以愉快的調(diào)用服務(wù)端的方法了,即實現(xiàn)了進(jìn)程間通信。
接下來我們研究一下其中的一些細(xì)節(jié)。先從客戶端我們定義的IBookManager對象和ServiceConnection對象。
深入細(xì)節(jié)
//定義IBookManager對象
private IBookManager bookManager;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//注釋1處,
Log.e(TAG, "onServiceConnected:" + service.getClass().getCanonicalName());
//注釋2處,獲取bookManager對象,注意這個傳入的service對象是一個BinderProxy對象
bookManager = IBookManager.Stub.asInterface(service);
Log.e(TAG, "onServiceConnected:" + bookManager.getClass().getCanonicalName());
try {
getBookList();
bookManager.registerListener(mOnNewBookArriveListener);
} catch (RemoteException e) {
e.printStackTrace();
Log.e(TAG, "onServiceConnected: error" + e.getMessage());
}
}
//...
};
我們打印了service的類名bookManager的類型,如下所示。
onServiceConnected:android.os.BinderProxy
onServiceConnected:com.hm.aidlserver.IBookManager.Stub.Proxy
說明當(dāng)綁定到服務(wù)端的Service的時候,服務(wù)端返回的service對象是一個BinderProxy類型的對象而我們在客戶端定義的bookManager最終指向了一個IBookManager.Stub.Proxy類型的對象。這點要注意,后面還要再說。
在注釋2處,調(diào)用了IBookManager.Stub的asInterface(android.os.IBinder obj)方法。
public static com.hm.aidlserver.IBookManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
//注釋1處,客戶端調(diào)用IBinder類的queryLocalInterface(String descriptor)方法,返回的是null
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.hm.aidlserver.IBookManager))) {
return ((com.hm.aidlserver.IBookManager) iin);
}
//注釋2處,客戶端最終返回的是一個代理對象
return new com.hm.aidlserver.IBookManager.Stub.Proxy(obj);
}
注意:asInterface方法的注釋1處,客戶端調(diào)用IBinder類的queryLocalInterface(String descriptor)方法,返回的是null。為什么呢?IBinder接口有兩個實現(xiàn)類,一個是Binder,一個是BinderProxy。我們在onServiceConnected(ComponentName name, IBinder service)方法中得到的service是一個BinderProxy類型的對象。
BinderProxy的queryLocalInterface(String descriptor)方法直接返回的是null。
public IInterface queryLocalInterface(String descriptor) {
return null;
}
asInterface方法的注釋2處,客戶端最終返回的是一個代理對象。也就是說我們客戶端的bookManager對象是一個IBookManager.Stub.Proxy對象。我們獲取書籍列表和添加書籍都是調(diào)用IBookManager.Stub.Proxy類中的方法,接下來看一下。
private static class Proxy implements com.hm.aidlserver.IBookManager {
//注釋1處
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 java.util.List<com.hm.aidlserver.Book> getBookList() throws android.os.RemoteException {
//構(gòu)建發(fā)送到服務(wù)端的數(shù)據(jù)
android.os.Parcel _data = android.os.Parcel.obtain();
//構(gòu)建服務(wù)端返回的數(shù)據(jù)
android.os.Parcel _reply = android.os.Parcel.obtain();
//要獲取的書籍列表
java.util.List<com.hm.aidlserver.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
//注釋1處,標(biāo)記調(diào)用服務(wù)端的getBookList方法
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
//獲取查詢到的書籍列表
_result = _reply.createTypedArrayList(com.hm.aidlserver.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
//返回結(jié)果
return _result;
}
@Override
public void addBook(com.hm.aidlserver.Book book) throws android.os.RemoteException {
//構(gòu)建傳到服務(wù)端的數(shù)據(jù)
android.os.Parcel _data = android.os.Parcel.obtain();
//構(gòu)建服務(wù)端返回的數(shù)據(jù),添加數(shù)據(jù)其實我們是沒有要求返回數(shù)據(jù)的
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book != null)) {
_data.writeInt(1);
//將book對象寫入到data中
book.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
//注釋1處,標(biāo)記調(diào)用服務(wù)端的addBook方法
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
注釋1處,Proxy類中的mRemote就是一個BinderProxy對象。
BinderProxy的transact(int code, Parcel data, Parcel reply, int flags)方法。
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
//檢查數(shù)據(jù)大小,不能大于800K
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
//...
try {
//注釋1處,
return transactNative(code, data, reply, flags);
} finally {
//...
}
}
注釋1處,調(diào)用了BinderProxy的transactNative(int code, Parcel data, Parcel reply, int flags)方法,這是一個本地方法,最終會調(diào)用服務(wù)端Binder對象的transact方法。這個Binder對象就是我們在服務(wù)端Service中返回的對象(IBookManager.Stub類型)。
/**
* 實現(xiàn)IBookManager接口中的方法
*/
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
}
我們看一下IBookManager.Stub繼承了Binder類,并沒有重寫transact方法
Binder類transact方法
public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
int flags) throws RemoteException {
if (data != null) {
//讀取客戶端傳遞的數(shù)據(jù)
data.setDataPosition(0);
}
//注釋1處,調(diào)用onTransact方法
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
//設(shè)置返回給客戶端的數(shù)據(jù)
reply.setDataPosition(0);
}
return r;
}
注釋1處,調(diào)用了onTransact方法,IBookManager.Stub的重寫了onTransact方法,我們看一下。
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
throws android.os.RemoteException {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_getBookList: {
data.enforceInterface(descriptor);
java.util.List<com.hm.aidlserver.Book> _result = this.getBookList();
reply.writeNoException();
//返回數(shù)據(jù)
reply.writeTypedList(_result);
//返回true表示調(diào)用成功
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(descriptor);
com.hm.aidlserver.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.hm.aidlserver.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
//添加書籍
this.addBook(_arg0);
reply.writeNoException();
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
參考鏈接
- 《Android開發(fā)藝術(shù)探索》
- 寫給 Android 應(yīng)用工程師的 Binder 原理剖析