#### 2.3.3 Binder
Binder是一個很深入的話題,筆者也看過一些別人寫的Binder相關的文章,發現很少有人能把它介紹清楚,不是深入代碼細節不能自拔,就是長篇大論不知所云,看完后都是暈暈的感覺。所以,本節筆者不打算深入探討Binder的底層細節,因為Binder太復雜了。本節的側重點是介紹Binder的使用以及上層原理,為接下來的幾節內容做鋪墊。
* 直觀來說,Binder是Android中的一個類,它繼承了IBinder接口。
* 從IPC角度來說,Binder是Android中的一種跨進程通信方式,Binder還可以理解為一種虛擬的物理設備,它的設備驅動是/dev/binder,該通信方式在Linux中沒有;
* 從Android Framework角度來說,Binder是ServiceManager連接各種Manager(ActivityManager、WindowManager,等等)和相應ManagerService的橋梁;
* 從Android應用層來說,Binder是客戶端和服務端進行通信的媒介,當bindService的時候,服務端會返回一個包含了服務端業務調用的Binder對象,通過這個Binder對象,客戶端就可以獲取服務端提供的服務或者數據,這里的服務包括普通服務和基于AIDL的服務。
:-: 
Binder流程圖
**Android開發中,Binder主要用在Service中,包括AIDL和Messenger,其中普通Service中的Binder不涉及進程間通信,所以較為簡單,無法觸及Binder的核心,而Messenger的底層其實是AIDL,Messenger、AIDL、ContentProvider的底層實現都Binder,所以這里選擇用AIDL來分析Binder的工作機制**。
為了分析Binder的工作機制,我們需要新建一個AIDL示例,SDK會自動為我們生產AIDL所對應的Binder類,然后我們就可以分析Binder的工作過程。還是采用本章開始時用的例子,新建Java包com.ryg.chapter_2.aidl,然后新建三個文件Book.java、Book.aidl和IBookManager.aidl,代碼如下所示。
**Book.java**
```
package com.ryg.chapter_2.aidl;
import android.os.Parcel;
import android.os.Parcelable;
public class Book implements Parcelable {
public int bookId;
public String bookName;
public Book() {
}
public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(bookId);
out.writeString(bookName);
}
public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {
public Book createFromParcel(Parcel in) {
return new Book(in);
}
public Book[] newArray(int size) {
return new Book[size];
}
};
private Book(Parcel in) {
bookId = in.readInt();
bookName = in.readString();
}
@Override
public String toString() {
return String.format("[bookId:%s, bookName:%s]", bookId, bookName);
}
}
```
**Book.aidl**
```
package com.ryg.chapter_2.aidl;
parcelable Book;
```
**IBookManager.aidl**
```
package com.ryg.chapter_2.aidl;
import com.ryg.chapter_2.aidl.Book;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
}
```
上面三個文件中,
* Book.java是一個表示圖書信息的類,它實現了Parcelable接口。
* Book.aidl是Book類在AIDL中的聲明。
* IBookManager.aidl是我們定義的一個接口,里面有兩個方法:getBookList和addBook,其中getBookList用于從遠程服務端獲取圖書列表,而addBook用于往圖書列表中添加一本書,當然這兩個方法主要是示例用,不一定要有實際意義。
我們可以看到,**盡管Book類已經和IBookManager位于相同的包中,但是在IBookManager中仍然要導入Book類,這就是AIDL的特殊之處**。
下面我們先看一下系統為IBookManager.aidl生產的Binder類,在gen目錄下的com.ryg.chapter_2.aidl包中有一個IBookManager.java的類,這就是我們要找的類。接下來我們需要根據這個系統生成的Binder類來分析Binder的工作原理,代碼如下:
**服務器端的代碼**:
```
/**
*This file is auto-generated. DO NOT MODIFY.
*Original file: E:\\workspace\\Chapter_2\\src\\com\\ryg\\chapter_2\\aidl\\IBookManager.aidl
*/
package com.ryg.chapter_2.aidl;
public interface IBookManager extends android.os.IInterface {
/* Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.ryg.chapter_2.aidl.IBookManager {
private static final java.lang.String DESCRIPTOR = "com.ryg.chapter_2.aidl.IBookManager";
/*Construct the stub at attach it to the interface. */
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/*
* Cast an IBinder object into an com.ryg.chapter_2.aidl.IBookManager
* interface, generating a proxy if needed.
*/
public static com.ryg.chapter_2.aidl.IBookManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin ! = null) && (iin instanceof com.ryg.chapter_2.aidl.
IBookManager))) {
return ((com.ryg.chapter_2.aidl.IBookManager) iin);
}
return new com.ryg.chapter_2.aidl.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.Remote-Exception {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBookList: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.ryg.chapter_2.aidl.Book> _result = this.
getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
com.ryg.chapter_2.aidl.Book _arg0;
if ((0 ! = data.readInt())) {
_arg0 = com.ryg.chapter_2.aidl.Book.CREATOR.create-
FromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.ryg.chapter_2.aidl.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.ryg.chapter_2.aidl.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.ryg.chapter_2.aidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data,_reply, 0);
_reply.readException();
_result = _reply
.createTypedArrayList(com.ryg.chapter_2.aidl.
Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addBook(com.ryg.chapter_2.aidl.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();
}
}
}
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.ryg.chapter_2.aidl.Book> getBookList()
throws android.os.RemoteException;
public void addBook(com.ryg.chapter_2.aidl.Book book)
throws android.os.RemoteException;
}
```
:-: 
系統為IBookManager.aidl自動生成的gen目錄下的IBookManager.java類的結構圖
>[info]注意,上圖其中的某些方法并不是該小章節的方法,而是整個第2章binder知識所命名的方法
上述代碼是系統生成的,為了方便查看筆者稍微做了一下格式上的調整。
在gen目錄下,可以看到根據IBookManager.aidl系統為我們生成了**IBookManager.java這個類,它繼承了IInterface這個接口,同時它自己也還是個接口,所有可以在Binder中傳輸的接口都需要繼承IInterface接口**。
這個類剛開始看起來邏輯混亂,但是實際上還是很清晰的,通過它我們可以清楚地了解到Binder的工作機制。
這個類的結構其實很簡單,
* 首先,它聲明了兩個方法getBookList和addBook,顯然這就是我們在IBookManager.aidl中所聲明的方法,同時它還聲明了兩個整型的id(`TRANSACTION_getBookList
`和`TRANSACTION_addBook`)分別用于標識這兩個方法,這兩個id用于標識在transact過程中客戶端所請求的到底是哪個方法。
* 接著,**它聲明了一個內部類Stub,這個Stub就是一個Binder類,當客戶端和服務端都位于同一個進程時,方法調用,不會走跨進程的transact過程,而當兩者位于不同進程時,方法調用,需要走transact過程,這個邏輯由Stub的內部代理類Proxy來完成**。這么來看,IBookManager這個接口的確很簡單,但是我們也應該認識到,這個**接口的核心實現就是它的內部類Stub和Stub的內部代理類Proxy**,
完整的代碼(整個第2章的)如下圖所示(idea編輯器自動生成的),

~~~
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: E:\\AndroidStudioProjects\\AndroidDevelopArtistic\\Chapter_2\\src\\main\\aidl
* \\com\\ryg\\chapter_2\\aidl\\IBookManager.aidl
*/
package com.ryg.chapter_2.aidl;
public interface IBookManager extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.ryg.chapter_2.aidl.IBookManager {
private static final java.lang.String DESCRIPTOR = "com.ryg.chapter_2.aidl.IBookManager";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.ryg.chapter_2.aidl.IBookManager interface,
* generating a proxy if needed.
*/
public static com.ryg.chapter_2.aidl.IBookManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.ryg.chapter_2.aidl.IBookManager))) {
return ((com.ryg.chapter_2.aidl.IBookManager) iin);
}
return new com.ryg.chapter_2.aidl.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 {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBookList: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.ryg.chapter_2.aidl.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
com.ryg.chapter_2.aidl.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.ryg.chapter_2.aidl.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_registerListener: {
data.enforceInterface(DESCRIPTOR);
com.ryg.chapter_2.aidl.IOnNewBookArrivedListener _arg0;
_arg0 = com.ryg.chapter_2.aidl.IOnNewBookArrivedListener.Stub.asInterface(data.readStrongBinder());
this.registerListener(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_unregisterListener: {
data.enforceInterface(DESCRIPTOR);
com.ryg.chapter_2.aidl.IOnNewBookArrivedListener _arg0;
_arg0 = com.ryg.chapter_2.aidl.IOnNewBookArrivedListener.Stub.asInterface(data.readStrongBinder());
this.unregisterListener(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.ryg.chapter_2.aidl.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.ryg.chapter_2.aidl.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.ryg.chapter_2.aidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.ryg.chapter_2.aidl.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addBook(com.ryg.chapter_2.aidl.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();
}
}
@Override
public void registerListener(com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((listener != null)) ? (listener.asBinder()) : (null)));
mRemote.transact(Stub.TRANSACTION_registerListener, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void unregisterListener(com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((listener != null)) ? (listener.asBinder()) : (null)));
mRemote.transact(Stub.TRANSACTION_unregisterListener, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_registerListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_unregisterListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
}
public java.util.List<com.ryg.chapter_2.aidl.Book> getBookList() throws android.os.RemoteException;
public void addBook(com.ryg.chapter_2.aidl.Book book) throws android.os.RemoteException;
public void registerListener(com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException;
public void unregisterListener(com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException;
}
~~~
:-: 
系統為IBookManager.aidl自動生成的gen目錄下的IBookManager.java類的結構圖
下面詳細介紹針對這兩個類的每個方法的含義。
* **DESCRIPTOR**
**Binder的唯一標識,一般用當前Binder的類名表示**,比如本例中的“com.ryg. chapter_2.aidl.IBookManager”。
* **asInterface(android.os.IBinder obj)**
**用于將服務端的Binder對象轉換成客戶端所需的AIDL接口類型的對象,這種轉換過程是區分進程的,如果客戶端和服務端位于同一進程,那么此方法返回的就是服務端的Stub對象本身,否則返回的是系統封裝后的Stub.proxy對象**。
* **asBinder**
此方法用于返回當前Binder對象。
* **onTransact**
* **這個方法運行在服務端中的Binder線程池中**,執行過程:**當客戶端發起跨進程請求時,遠程請求會通過系統底層封裝后交由此方法來處理。該方法的原型為public Boolean onTransact (int code, android.os.Parcel data, android.os.Parcel reply, int flags)。服務端通過code可以確定客戶端所請求的目標方法是什么,接著從data中取出目標方法所需的參數(如果目標方法有參數的話),然后執行目標方法。當目標方法執行完畢后,就向reply中寫入返回值(如果目標方法有返回值的話), onTransact方法的執行過程就是這樣的**。
需要注意的是,**如果此方法返回false,那么客戶端的請求會失敗,因此我們可以利用這個特性來做權限驗證,畢竟我們也不希望隨便一個進程都能遠程調用我們的服務**。
* **Proxy#getBookList**
~~~
@Override
public java.util.List<com.ryg.chapter_2.aidl.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.ryg.chapter_2.aidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.ryg.chapter_2.aidl.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
~~~
這個方法**運行在客戶端**,當客戶端遠程調用此方法時,它的內部實現是這樣的:首先創建該方法所需要的輸入型Parcel對象_data、輸出型Parcel對象_reply和返回值對象List;然后把該方法的參數信息寫入_data中(如果有參數的話);接著調用transact方法來發起**RPC(遠程過程調用**)請求,同時當前線程掛起;然后服務端的onTransact方法會被調用,直到RPC過程返回后,當前線程繼續執行,并從_reply中取出RPC過程的返回結果;最后返回_reply中的數據。
* **Proxy#addBook**
這個方法**運行在客戶端**,它的執行過程和getBookList是一樣的,addBook沒有返回值,所以它不需要從_reply中取出返回值。
通過上面的分析,讀者應該已經了解了Binder的工作機制,但是有兩點還是需要額外說明一下:
1. 首先,當客戶端發起遠程請求時,由于當前線程會被掛起直至服務端進程返回數據,所以如果一個遠程方法是很耗時的,那么**不能在UI線程中發起此遠程請求**;
2. 其次,由于服務端的Binder方法運行在Binder的線程池中,所以**Binder方法不管是否耗時都應該采用同步的方式去實現,因為它已經運行在一個線程中了**。
為了更好地說明Binder,下面給出一個Binder的工作機制圖,如圖2-5所示。從下圖來看,**binder更像是一個數據通道**。
:-: 
圖2-5 Binder的工作機制
從上述分析過程來看,我們**完全可以不提供AIDL文件即可實現Binder,之所以提供AIDL文件,是為了方便系統為我們生成代碼**。
系統根據AIDL文件生成Java文件的格式是固定的,我們可以拋開AIDL文件直接寫一個Binder出來,接下來我們就介紹**如何手動寫一個Binder**。還是上面的例子,但是這次我們不提供AIDL文件。參考上面系統自動生成的IBookManager.java這個類的代碼,可以發現這個類是相當有規律的,根據它的特點,我們完全可以自己寫一個和它一模一樣的類出來,然后這個不借助AIDL文件的Binder就完成了。但是我們發現系統生成的類看起來結構不清晰,我們想試著對它進行結構上的調整,**可以發現這個類主要由兩部分組成,首先它本身是一個Binder的接口(繼承了IInterface),其次它的內部有個Stub類,這個類就是個Binder**。還記得我們怎么寫一個Binder的服務端嗎?代碼如下所示。
private final IBookManager.Stub mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
synchronized (mBookList) {
return mBookList;
}
}
@Override
public void addBook(Book book) throws RemoteException {
synchronized (mBookList) {
if (! mBookList.contains(book)) {
mBookList.add(book);
}
}
}
}
**首先我們會實現一個創建了一個Stub對象并在內部實現IBookManager的接口方法,然后在Service的onBind中返回這個Stub對象。因此,從這一點來看,我們完全可以把Stub類提取出來直接作為一個獨立的Binder類來實現,這樣IBookManager中就只剩接口本身了,通過這種分離的方式可以讓它的結構變得清晰點**。
根據上面的思想,**手動實現一個Binder可以通過如下步驟來完成**:
(1)聲明一個AIDL性質的接口,只需要繼承IInterface接口即可,IInterface接口中只有一個asBinder方法。這個接口的實現如下:
public interface IBookManager extends IInterface {
static final String DESCRIPTOR = "com.ryg.chapter_2.manualbinder.IBookManager";
static final int TRANSACTION_getBookList = IBinder.FIRST_CALL_TRANSA-CTION + 0;
static final int TRANSACTION_addBook = IBinder.FIRST_CALL_TRANSACTION+ 1;
public List<Book> getBookList() throws RemoteException;
public void addBook(Book book) throws RemoteException;
}
可以看到,**在接口中聲明了一個Binder描述符和另外兩個id,這兩個id分別表示的是getBookList和addBook方法**,這段代碼原本也是系統生成的,我們仿照系統生成的規則去手動書寫這部分代碼。如果我們有三個方法,應該怎么做呢?很顯然,我們要再聲明一個id,然后按照固定模式聲明這個新方法即可,這個比較好理解,不再多說。
(2)實現Stub類和Stub類中的Proxy代理類,這段代碼我們可以自己寫,但是寫出來后會發現和系統自動生成的代碼是一樣的,因此這個Stub類我們只需要參考系統生成的代碼即可,只是結構上需要做一下調整,調整后的代碼如下所示。
[BookManagerImpl.java](https://github.com/singwhatiwanna/android-art-res/blob/master/Chapter_2/src/com/ryg/chapter_2/manualbinder/BookManagerImpl.java)
```
package com.ryg.chapter_2.manualbinder;
import java.util.List;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
public class BookManagerImpl extends Binder implements IBookManager {
/** Construct the stub at attach it to the interface. */
public BookManagerImpl() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an IBookManager interface, generating a proxy
* if needed.
*/
public static IBookManager asInterface(IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof IBookManager))) {
return ((IBookManager) iin);
}
return new BookManagerImpl.Proxy(obj);
}
@Override
public IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBookList: {
data.enforceInterface(DESCRIPTOR);
List<Book> result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
Book arg0;
if ((0 != data.readInt())) {
arg0 = Book.CREATOR.createFromParcel(data);
} else {
arg0 = null;
}
this.addBook(arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
@Override
public List<Book> getBookList() throws RemoteException {
// TODO 待實現
return null;
}
@Override
public void addBook(Book book) throws RemoteException {
// TODO 待實現
}
private static class Proxy implements IBookManager {
private IBinder mRemote;
Proxy(IBinder remote) {
mRemote = remote;
}
@Override
public IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public List<Book> getBookList() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
List<Book> result;
try {
data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(TRANSACTION_getBookList, data, reply, 0);
reply.readException();
result = reply.createTypedArrayList(Book.CREATOR);
} finally {
reply.recycle();
data.recycle();
}
return result;
}
@Override
public void addBook(Book book) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(DESCRIPTOR);
if ((book != null)) {
data.writeInt(1);
book.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
mRemote.transact(TRANSACTION_addBook, data, reply, 0);
reply.readException();
} finally {
reply.recycle();
data.recycle();
}
}
}
}
```
通過將上述代碼和系統生成的代碼對比,可以發現簡直是一模一樣的。也許有人會問:**既然和系統生成的一模一樣,那我們為什么要手動去寫呢**?我們**在實際開發中完全可以通過AIDL文件讓系統去自動生成,手動去寫的意義在于可以讓我們更加理解Binder的工作原理,同時也提供了一種不通過AIDL文件來實現Binder的新方式**。也就是說,**AIDL文件并不是實現Binder的必需品。如果是我們手寫的Binder,那么在服務端只需要創建一個BookManagerImpl的對象并在Service的onBind方法中返回即可。最后,是否手動實現Binder沒有本質區別,二者的工作原理完全一樣,AIDL文件的本質是系統為我們提供了一種快速實現Binder的工具,僅此而已**。
接下來,我們介紹Binder的兩個很重要的方法**linkToDeath和unlinkToDeath**。我們知道,**Binder運行在服務端進程,如果服務端進程由于某種原因異常終止,這個時候我們到服務端的Binder連接斷裂(稱之為Binder死亡),會導致我們的遠程調用失敗。更為關鍵的是,如果我們不知道Binder連接已經斷裂,那么客戶端的功能就會受到影響**。
**為了解決這個問題,Binder中提供了兩個配對的方法linkToDeath和unlinkToDeath,通過linkToDeath我們可以給Binder設置一個死亡代理,當Binder死亡時,我們就會收到通知,這個時候我們就可以重新發起連接請求從而恢復連接**。那么到底如何給Binder設置死亡代理呢?也很簡單。
* 首先,**聲明一個DeathRecipient對象。DeathRecipient是一個接口,其內部只有一個方法binderDied,我們需要實現這個方法,當Binder死亡的時候,系統就會回調binderDied方法,然后我們就可以移出之前綁定的binder代理并重新綁定遠程服務**:
private IBinder.DeathRecipient mDeathRecipient = new IBinder.Death-
Recipient() {
@Override
public void binderDied() {
if (mBookManager == null)
return;
mBookManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
mBookManager = null;
// TODO:這里重新綁定遠程Service
}
};
* 其次,**在客戶端綁定遠程服務成功后,給binder設置死亡代理**:
```
mService = IMessageBoxManager.Stub.asInterface(binder);
binder.linkToDeath(mDeathRecipient, 0);
```
其中linkToDeath的第二個參數是個標記位,我們直接設為0即可。
**經過上面兩個步驟,就給我們的Binder設置了死亡代理,當Binder死亡的時候我們就可以收到通知了。另外,通過Binder的方法isBinderAlive也可以判斷Binder是否死亡**。
到這里,IPC的基礎知識就介紹完畢了,下面開始進入正題,直面形形色色的進程間通信方式。
- 前言
- 第1章 Activity的生命周期和啟動模式
- 1.1 Activity的生命周期全面分析
- 1.1.1 典型情況下的生命周期分析
- 1.1.2 異常情況下的生命周期分析
- 1.2 Activity的啟動模式
- 1.2.1 Activity的LaunchMode
- 1.2.2 Activity的Flags
- 1.3 IntentFilter的匹配規則
- 第2章 IPC機制
- 2.1 Android IPC簡介
- 2.2 Android中的多進程模式
- 2.2.1 開啟多進程模式
- 2.2.2 多進程模式的運行機制
- 2.3 IPC基礎概念介紹
- 2.3.1 Serializable接口
- 2.3.2 Parcelable接口
- 2.3.3 Binder
- 2.4 Android中的IPC方式
- 2.4.1 使用Bundle
- 2.4.2 使用文件共享
- 2.4.3 使用Messenger
- 2.4.4 使用AIDL
- 2.4.5 使用ContentProvider
- 2.4.6 使用Socket
- 2.5 Binder連接池
- 2.6 選用合適的IPC方式
- 第3章 View的事件體系
- 3.1 View基礎知識
- 3.1.1 什么是View
- 3.1.2 View的位置參數
- 3.1.3 MotionEvent和TouchSlop
- 3.1.4 VelocityTracker、GestureDetector和Scroller
- 3.2 View的滑動
- 3.2.1 使用scrollTo/scrollBy
- 3.2.2 使用動畫
- 3.2.3 改變布局參數
- 3.2.4 各種滑動方式的對比
- 3.3 彈性滑動
- 3.3.1 使用Scroller7
- 3.3.2 通過動畫
- 3.3.3 使用延時策略
- 3.4 View的事件分發機制
- 3.4.1 點擊事件的傳遞規則
- 3.4.2 事件分發的源碼解析
- 3.5 View的滑動沖突
- 3.5.1 常見的滑動沖突場景
- 3.5.2 滑動沖突的處理規則
- 3.5.3 滑動沖突的解決方式
- 第4章 View的工作原理
- 4.1 初識ViewRoot和DecorView
- 4.2 理解MeasureSpec
- 4.2.1 MeasureSpec
- 4.2.2 MeasureSpec和LayoutParams的對應關系
- 4.3 View的工作流程
- 4.3.1 measure過程
- 4.3.2 layout過程
- 4.3.3 draw過程
- 4.4 自定義View
- 4.4.1 自定義View的分類
- 4.4.2 自定義View須知
- 4.4.3 自定義View示例
- 4.4.4 自定義View的思想
- 第5章 理解RemoteViews
- 5.1 RemoteViews的應用
- 5.1.1 RemoteViews在通知欄上的應用
- 5.1.2 RemoteViews在桌面小部件上的應用
- 5.1.3 PendingIntent概述
- 5.2 RemoteViews的內部機制
- 5.3 RemoteViews的意義
- 第6章 Android的Drawable
- 6.1 Drawable簡介
- 6.2 Drawable的分類
- 6.2.1 BitmapDrawable2
- 6.2.2 ShapeDrawable
- 6.2.3 LayerDrawable
- 6.2.4 StateListDrawable
- 6.2.5 LevelListDrawable
- 6.2.6 TransitionDrawable
- 6.2.7 InsetDrawable
- 6.2.8 ScaleDrawable
- 6.2.9 ClipDrawable
- 6.3 自定義Drawable
- 第7章 Android動畫深入分析
- 7.1 View動畫
- 7.1.1 View動畫的種類
- 7.1.2 自定義View動畫
- 7.1.3 幀動畫
- 7.2 View動畫的特殊使用場景
- 7.2.1 LayoutAnimation
- 7.2.2 Activity的切換效果
- 7.3 屬性動畫
- 7.3.1 使用屬性動畫
- 7.3.2 理解插值器和估值器 /
- 7.3.3 屬性動畫的監聽器
- 7.3.4 對任意屬性做動畫
- 7.3.5 屬性動畫的工作原理
- 7.4 使用動畫的注意事項
- 第8章 理解Window和WindowManager
- 8.1 Window和WindowManager
- 8.2 Window的內部機制
- 8.2.1 Window的添加過程
- 8.2.2 Window的刪除過程
- 8.2.3 Window的更新過程
- 8.3 Window的創建過程
- 8.3.1 Activity的Window創建過程
- 8.3.2 Dialog的Window創建過程
- 8.3.3 Toast的Window創建過程
- 第9章 四大組件的工作過程
- 9.1 四大組件的運行狀態
- 9.2 Activity的工作過程
- 9.3 Service的工作過程
- 9.3.1 Service的啟動過程
- 9.3.2 Service的綁定過程
- 9.4 BroadcastReceiver的工作過程
- 9.4.1 廣播的注冊過程
- 9.4.2 廣播的發送和接收過程
- 9.5 ContentProvider的工作過程
- 第10章 Android的消息機制
- 10.1 Android的消息機制概述
- 10.2 Android的消息機制分析
- 10.2.1 ThreadLocal的工作原理
- 10.2.2 消息隊列的工作原理
- 10.2.3 Looper的工作原理
- 10.2.4 Handler的工作原理
- 10.3 主線程的消息循環
- 第11章 Android的線程和線程池
- 11.1 主線程和子線程
- 11.2 Android中的線程形態
- 11.2.1 AsyncTask
- 11.2.2 AsyncTask的工作原理
- 11.2.3 HandlerThread
- 11.2.4 IntentService
- 11.3 Android中的線程池
- 11.3.1 ThreadPoolExecutor
- 11.3.2 線程池的分類
- 第12章 Bitmap的加載和Cache
- 12.1 Bitmap的高效加載
- 12.2 Android中的緩存策略
- 12.2.1 LruCache
- 12.2.2 DiskLruCache
- 12.2.3 ImageLoader的實現446
- 12.3 ImageLoader的使用
- 12.3.1 照片墻效果
- 12.3.2 優化列表的卡頓現象
- 第13章 綜合技術
- 13.1 使用CrashHandler來獲取應用的crash信息
- 13.2 使用multidex來解決方法數越界
- 13.3 Android的動態加載技術
- 13.4 反編譯初步
- 13.4.1 使用dex2jar和jd-gui反編譯apk
- 13.4.2 使用apktool對apk進行二次打包
- 第14章 JNI和NDK編程
- 14.1 JNI的開發流程
- 14.2 NDK的開發流程
- 14.3 JNI的數據類型和類型簽名
- 14.4 JNI調用Java方法的流程
- 第15章 Android性能優化
- 15.1 Android的性能優化方法
- 15.1.1 布局優化
- 15.1.2 繪制優化
- 15.1.3 內存泄露優化
- 15.1.4 響應速度優化和ANR日志分析
- 15.1.5 ListView和Bitmap優化
- 15.1.6 線程優化
- 15.1.7 一些性能優化建議
- 15.2 內存泄露分析之MAT工具
- 15.3 提高程序的可維護性