Android 手寫Binder 教你理解android中的程式間通訊

希爾瓦娜斯女神發表於2016-01-27

關於Binder,我就不解釋的太多了,網上一搜資料一堆,但是估計還是很多人理解的有困難。今天就教你如何從 app層面來理解好Binder。

其實就從我們普通app開發者的角度來看,僅僅對於android應用層的話,Binder就是客戶端和服務端進行通訊的媒介。

AIDL就是我們理解Binder 最好的事例。

我們都知道 我們寫好aidl 檔案以後,開發工具 會自動幫我們生成好程式碼。實際上 我們最終apk裡面 是隻有這些程式碼的,我們寫的aidl檔案

是不會被打包進去的,也就是說aidl檔案 實際上 就是我們用來 生成 實際binder程式碼用的。所以 我們只要能夠分析好,ide自動幫我們生成的

程式碼,就可以自己手寫binder,從而在app層面上真正理解binder的用法和含義 以及原理。

首先我先來定義一個實體類:Person.java

 1 package com.example.administrator.writebindercodeexample;
 2 
 3 import android.os.Parcel;
 4 import android.os.Parcelable;
 5 
 6 /**
 7  * Created by Administrator on 2016/1/27.
 8  */
 9 public class Person implements Parcelable {
10 
11     private String name;
12 
13     public void setName(String name) {
14         this.name = name;
15     }
16 
17     public void setGender(int gender) {
18         this.gender = gender;
19     }
20 
21     public int getGender() {
22         return gender;
23     }
24 
25     public String getName() {
26         return name;
27     }
28 
29     private int gender;
30 
31     @Override
32     public int describeContents() {
33         return 0;
34     }
35 
36     @Override
37     public void writeToParcel(Parcel dest, int flags) {
38         dest.writeString(this.name);
39         dest.writeInt(this.gender);
40     }
41 
42     public Person() {
43     }
44 
45     protected Person(Parcel in) {
46         this.name = in.readString();
47         this.gender = in.readInt();
48     }
49 
50     public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
51         public Person createFromParcel(Parcel source) {
52             return new Person(source);
53         }
54 
55         public Person[] newArray(int size) {
56             return new Person[size];
57         }
58     };
59 }

注意看  我們這個person 類 是實現了android自帶的序列化介面的,所以 如果你要在aidl裡使用這個類,那你必須要額外在aidl裡生命下 這個類。

1 // Person.aidl.aidl
2 package com.example.administrator.writebindercodeexample;
3 
4 // Declare any non-default types here with import statements
5 parcelable Person;
 1 // IPersonManager.aidl
 2 package com.example.administrator.writebindercodeexample;
 3 
 4 // Declare any non-default types here with import statements
 5 import com.example.administrator.writebindercodeexample.Person;
 6 interface IPersonManager {
 7     List<Person> getPersonList();
 8     //關於這個引數in 其實你不加也是可以編譯通過的,這裡我就先加一下 具體引數的意義 以後會說
 9     void addPerson(in Person person);
10 }

好,然後給你們看一下 檔案結構:

好 這裡就是一個典型的 應用aidl 技術的 一個例子,我們現在 讓studio 編譯這個project,然後看看生成的binder程式碼。 把這份binder程式碼 分析好了,我們以後就可以不借助ide 來自己手寫binder了。

我們來看看 生成的程式碼在哪裡:

最後我們來看一下 這個生成的程式碼 是啥樣的:

  1 /*
  2  * This file is auto-generated.  DO NOT MODIFY.
  3  * Original file: C:\\Users\\Administrator\\WriteBinderCodeExample\\app\\src\\main\\aidl\\com\\example\\administrator\\writebindercodeexample\\IPersonManager.aidl
  4  */
  5 package com.example.administrator.writebindercodeexample;
  6 public interface IPersonManager extends android.os.IInterface
  7 {
  8 /** Local-side IPC implementation stub class. */
  9 public static abstract class Stub extends android.os.Binder implements com.example.administrator.writebindercodeexample.IPersonManager
 10 {
 11 private static final java.lang.String DESCRIPTOR = "com.example.administrator.writebindercodeexample.IPersonManager";
 12 /** Construct the stub at attach it to the interface. */
 13 public Stub()
 14 {
 15 this.attachInterface(this, DESCRIPTOR);
 16 }
 17 /**
 18  * Cast an IBinder object into an com.example.administrator.writebindercodeexample.IPersonManager interface,
 19  * generating a proxy if needed.
 20  */
 21 public static com.example.administrator.writebindercodeexample.IPersonManager asInterface(android.os.IBinder obj)
 22 {
 23 if ((obj==null)) {
 24 return null;
 25 }
 26 android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
 27 if (((iin!=null)&&(iin instanceof com.example.administrator.writebindercodeexample.IPersonManager))) {
 28 return ((com.example.administrator.writebindercodeexample.IPersonManager)iin);
 29 }
 30 return new com.example.administrator.writebindercodeexample.IPersonManager.Stub.Proxy(obj);
 31 }
 32 @Override public android.os.IBinder asBinder()
 33 {
 34 return this;
 35 }
 36 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
 37 {
 38 switch (code)
 39 {
 40 case INTERFACE_TRANSACTION:
 41 {
 42 reply.writeString(DESCRIPTOR);
 43 return true;
 44 }
 45 case TRANSACTION_getPersonList:
 46 {
 47 data.enforceInterface(DESCRIPTOR);
 48 java.util.List<com.example.administrator.writebindercodeexample.Person> _result = this.getPersonList();
 49 reply.writeNoException();
 50 reply.writeTypedList(_result);
 51 return true;
 52 }
 53 case TRANSACTION_addPerson:
 54 {
 55 data.enforceInterface(DESCRIPTOR);
 56 com.example.administrator.writebindercodeexample.Person _arg0;
 57 if ((0!=data.readInt())) {
 58 _arg0 = com.example.administrator.writebindercodeexample.Person.CREATOR.createFromParcel(data);
 59 }
 60 else {
 61 _arg0 = null;
 62 }
 63 this.addPerson(_arg0);
 64 reply.writeNoException();
 65 return true;
 66 }
 67 }
 68 return super.onTransact(code, data, reply, flags);
 69 }
 70 private static class Proxy implements com.example.administrator.writebindercodeexample.IPersonManager
 71 {
 72 private android.os.IBinder mRemote;
 73 Proxy(android.os.IBinder remote)
 74 {
 75 mRemote = remote;
 76 }
 77 @Override public android.os.IBinder asBinder()
 78 {
 79 return mRemote;
 80 }
 81 public java.lang.String getInterfaceDescriptor()
 82 {
 83 return DESCRIPTOR;
 84 }
 85 @Override public java.util.List<com.example.administrator.writebindercodeexample.Person> getPersonList() throws android.os.RemoteException
 86 {
 87 android.os.Parcel _data = android.os.Parcel.obtain();
 88 android.os.Parcel _reply = android.os.Parcel.obtain();
 89 java.util.List<com.example.administrator.writebindercodeexample.Person> _result;
 90 try {
 91 _data.writeInterfaceToken(DESCRIPTOR);
 92 mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);
 93 _reply.readException();
 94 _result = _reply.createTypedArrayList(com.example.administrator.writebindercodeexample.Person.CREATOR);
 95 }
 96 finally {
 97 _reply.recycle();
 98 _data.recycle();
 99 }
100 return _result;
101 }
102 //關於這個引數in 其實你不加也是可以編譯通過的,這裡我就先加一下 具體引數的意義 以後會說
103 
104 @Override public void addPerson(com.example.administrator.writebindercodeexample.Person person) throws android.os.RemoteException
105 {
106 android.os.Parcel _data = android.os.Parcel.obtain();
107 android.os.Parcel _reply = android.os.Parcel.obtain();
108 try {
109 _data.writeInterfaceToken(DESCRIPTOR);
110 if ((person!=null)) {
111 _data.writeInt(1);
112 person.writeToParcel(_data, 0);
113 }
114 else {
115 _data.writeInt(0);
116 }
117 mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
118 _reply.readException();
119 }
120 finally {
121 _reply.recycle();
122 _data.recycle();
123 }
124 }
125 }
126 static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
127 static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
128 }
129 public java.util.List<com.example.administrator.writebindercodeexample.Person> getPersonList() throws android.os.RemoteException;
130 //關於這個引數in 其實你不加也是可以編譯通過的,這裡我就先加一下 具體引數的意義 以後會說
131 
132 public void addPerson(com.example.administrator.writebindercodeexample.Person person) throws android.os.RemoteException;
133 }

看上去呢,雜亂無章, 但其實也就是100多行,所以 我調整了一下 這個程式碼的順序 ,你們可以看的更清楚,同時也增加了註釋:

 

  1 package com.example.administrator.aidlmessagetest;
  2 
  3 //為了讓大家看的更清楚 我把生成的binder程式碼 給拷貝到另外一個工程下面了,並且用ide 給他format
  4 //所以包名和我們一開始前面的程式碼都不一樣,大家理解意思就行。
  5 
  6 
  7 //從前面幾行就能看出來 生成的程式碼是一個 interface ,只不過這個interface是 android.os.IInterface 的子類!
  8 public interface IPersonManager extends android.os.IInterface {
  9 
 10     //並且這個介面裡 有一個靜態的抽象類Stub(注意這個名字是固定的 永遠都是Stub 不會是其他)
 11     //並且這個Stub是Binder的子類,並且實現了IPersonManager 這個介面
 12     public static abstract class Stub extends android.os.Binder implements com.example.administrator.aidlmessagetest.IPersonManager {
 13         //這個東西就是唯一的binder標示 可以看到就是IPersonManager的全路徑名
 14         private static final java.lang.String DESCRIPTOR = "com.example.administrator.aidlmessagetest.IPersonManager";
 15 
 16         /**
 17          * 這個就是Stub的構造方法,回顧一下 我們如果寫好aidl檔案以後 寫的service裡面 是怎麼寫的?
 18          *
 19          * private final IPersonManager.Stub mBinder = new IPersonManager.Stub() {}
 20          * 我們都是這麼寫的 對吧~~所以想想我們的service裡面的程式碼 就能輔助理解 這裡的程式碼了
 21          */
 22         public Stub() {
 23             this.attachInterface(this, DESCRIPTOR);
 24         }
 25 
 26 
 27         //這個方法 其實就做了一件事,如果是同一個程式,那麼就返回Stub物件本身
 28         //如果不是同一個程式,就返回Stub.Proxy這個代理物件了
 29         public static com.example.administrator.aidlmessagetest.IPersonManager asInterface(android.os.IBinder obj) {
 30             if ((obj == null)) {
 31                 return null;
 32             }
 33             android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
 34             //如果是同1個程式,也就是說程式內通訊的話 我們就返回括號內裡的物件
 35             if (((iin != null) && (iin instanceof com.example.administrator.aidlmessagetest.IPersonManager))) {
 36                 return ((com.example.administrator.aidlmessagetest.IPersonManager) iin);
 37             }
 38             //如果不是同一程式,是2個程式之間相互通訊,那我們就得返回這個Stub.Proxy 看上去叫Stub 代理的物件了
 39             return new com.example.administrator.aidlmessagetest.IPersonManager.Stub.Proxy(obj);
 40         }
 41 
 42         //返回當前物件
 43         @Override
 44         public android.os.IBinder asBinder() {
 45             return this;
 46         }
 47 
 48         //只有在多程式通訊的時候 才會呼叫這個方法 ,同一個程式是不會呼叫的。
 49 
 50         //首先 我們要明白 這個方法 一般情況下 都是返回true的,也只有返回true的時候才有意義,如果返回false了 就代表這個方法執行失敗,
 51         //所以我們通常是用這個方法來做許可權認證的,其實也很好理解,既然是多程式通訊,那麼我們服務端的程式當然不希望誰都能過來呼叫
 52         //所以許可權認證是必須的,關於許可權認證的程式碼 以後我再講 先略過。
 53 
 54         //除此之外 ,onTransact 這個方法 就是執行在Binder執行緒池中的,一般就是客戶端發起請求,然後android底層程式碼把這個客戶端發起的
 55         //請求 封裝成3個引數 來呼叫這個onTransact方法,第一個引數code 就代表客戶端想要呼叫服務端 方法的 標誌位。
 56         //其實也很好理解 服務端可能有n個方法 每個方法 都有一個對應的int值來代表,這個code就是這個int值,用來標示客戶端想呼叫的服務端的方法
 57         //data就是方法引數,reply就是方法返回值。都很好理解
 58 
 59         //其實隱藏了很重要的一點,這個方法既然是執行在binder執行緒池中的,所以在這個方法裡面呼叫的伺服器方法也是執行在Binder執行緒池中的,
 60         //所以我們要記得 如果你的服務端程式 有可能和多個客戶端相聯的話,你方法裡使用的那些引數 必須要是支援非同步的,否則的話
 61         //值就會錯亂了!這點一定要記住!結論就是Binder方法 一定要是同步方法!!!!!!
 62         @Override
 63         public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
 64             switch (code) {
 65                 case INTERFACE_TRANSACTION: {
 66                     reply.writeString(DESCRIPTOR);
 67                     return true;
 68                 }
 69                 case TRANSACTION_getPersonList: {
 70                     data.enforceInterface(DESCRIPTOR);
 71                     java.util.List<com.example.administrator.aidlmessagetest.Person> _result = this.getPersonList();
 72                     reply.writeNoException();
 73                     reply.writeTypedList(_result);
 74                     return true;
 75                 }
 76                 case TRANSACTION_addPerson: {
 77                     data.enforceInterface(DESCRIPTOR);
 78                     com.example.administrator.aidlmessagetest.Person _arg0;
 79                     if ((0 != data.readInt())) {
 80                         _arg0 = com.example.administrator.aidlmessagetest.Person.CREATOR.createFromParcel(data);
 81                     } else {
 82                         _arg0 = null;
 83                     }
 84                     this.addPerson(_arg0);
 85                     reply.writeNoException();
 86                     return true;
 87                 }
 88             }
 89             return super.onTransact(code, data, reply, flags);
 90         }
 91 
 92         //注意這裡的Proxy 這個類名也是不變的,從前文我們知道 只有在多程式通訊的情況下  才會返回這個代理的物件
 93         private static class Proxy implements com.example.administrator.aidlmessagetest.IPersonManager {
 94             private android.os.IBinder mRemote;
 95 
 96             Proxy(android.os.IBinder remote) {
 97                 mRemote = remote;
 98             }
 99 
100             @Override
101             public android.os.IBinder asBinder() {
102                 return mRemote;
103             }
104 
105             public java.lang.String getInterfaceDescriptor() {
106                 return DESCRIPTOR;
107             }
108 
109 
110             //這裡我們一共有2個方法 一個getPersonList 一個addPerson 我們就分析一個方法就可以了
111             //並且要知道 這2個方法執行在客戶端!!!!!!!!!!!!!!!!
112             //首先就是建立了3個物件_data 輸入物件,_reply輸出物件,_result返回值物件
113             //然後把引數資訊 寫入到_data裡,接著就呼叫了transact這個方法 來傳送rpc請求,然後接著
114             //當前執行緒掛起, 服務端的onTransace方法才被呼叫,呼叫結束以後 當前執行緒繼續執行,直到
115             //從_reply中取出rpc的返回結果 然後返回_reply的資料
116 
117             //所以這裡我們就要注意了,客戶端發起呼叫遠端請求時,當前客戶端的執行緒就會被掛起了,
118             //所以如果一個遠端方法 很耗時,我們客戶端就一定不能在ui main執行緒裡在發起這個rpc請求,不然就anr了。
119             @Override
120             public java.util.List<com.example.administrator.aidlmessagetest.Person> getPersonList() throws android.os.RemoteException {
121                 android.os.Parcel _data = android.os.Parcel.obtain();
122                 android.os.Parcel _reply = android.os.Parcel.obtain();
123                 java.util.List<com.example.administrator.aidlmessagetest.Person> _result;
124                 try {
125                     _data.writeInterfaceToken(DESCRIPTOR);
126                     mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);
127                     _reply.readException();
128                     _result = _reply.createTypedArrayList(com.example.administrator.aidlmessagetest.Person.CREATOR);
129                 } finally {
130                     _reply.recycle();
131                     _data.recycle();
132                 }
133                 return _result;
134             }
135 
136             //你看自動生成binder程式碼的時候 連你的註釋也一起拷貝過來了。。。。。是不是很有趣
137             //關於這個引數in 其實你不加也是可以編譯通過的,這裡我就先加一下 具體引數的意義 以後會說
138 
139             @Override
140             public void addPerson(com.example.administrator.aidlmessagetest.Person person) throws android.os.RemoteException {
141                 android.os.Parcel _data = android.os.Parcel.obtain();
142                 android.os.Parcel _reply = android.os.Parcel.obtain();
143                 try {
144                     _data.writeInterfaceToken(DESCRIPTOR);
145                     if ((person != null)) {
146                         _data.writeInt(1);
147                         person.writeToParcel(_data, 0);
148                     } else {
149                         _data.writeInt(0);
150                     }
151                     mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
152                     _reply.readException();
153                 } finally {
154                     _reply.recycle();
155                     _data.recycle();
156                 }
157             }
158         }
159 
160         static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
161         static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
162     }
163 
164     public java.util.List<com.example.administrator.aidlmessagetest.Person> getPersonList() throws android.os.RemoteException;
165 //關於這個引數in 其實你不加也是可以編譯通過的,這裡我就先加一下 具體引數的意義 以後會說
166 
167     public void addPerson(com.example.administrator.aidlmessagetest.Person person) throws android.os.RemoteException;
168 }

到這裡 相信大家 至少在應用層上面,就對Binder就一個很直觀的理解了,對於程式間通訊來說,具體的流程就分為如下幾步:

1.Client 發起遠端呼叫請求 也就是RPC 到Binder。同時將自己掛起,掛起的原因是要等待RPC呼叫結束以後返回的結果

2.Binder 收到RPC請求以後 把引數收集一下,呼叫transact方法,把RPC請求轉發給service端。

3.service端 收到rpc請求以後 就去執行緒池裡 找一個空閒的執行緒去走service端的 onTransact方法 ,實際上也就是真正在執行service端的 方法了,等方法執行結束 就把結果 寫回到binder中。

4.Binder 收到返回資料以後 就喚醒原來的Client 執行緒,返回結果。至此,一次程式間通訊 的過程就結束了

搞明白以後 我們就可以來嘗試著 手下一下Binder:(前面我們aidl 幫我們生成的binder 是人,也就是person,那這次我們自己寫的時候 就用狗吧,用DOG)

首先定義一個Dog.java: 實際上和person 一樣的 所以這裡暫時把程式碼摺疊起來。

 1 package com.example.administrator.writebindercodeexample;
 2 
 3 import android.os.Parcel;
 4 import android.os.Parcelable;
 5 
 6 /**
 7  * Created by Administrator on 2016/1/27.
 8  */
 9 public class Dog implements Parcelable {
10 
11     public int getGender() {
12         return gender;
13     }
14 
15     public String getName() {
16         return name;
17     }
18 
19     public void setGender(int gender) {
20         this.gender = gender;
21     }
22 
23     public void setName(String name) {
24         this.name = name;
25     }
26 
27     private int gender;
28     private String name;
29 
30 
31     @Override
32     public int describeContents() {
33         return 0;
34     }
35 
36     @Override
37     public void writeToParcel(Parcel dest, int flags) {
38         dest.writeInt(this.gender);
39         dest.writeString(this.name);
40     }
41 
42     public Dog() {
43     }
44 
45     protected Dog(Parcel in) {
46         this.gender = in.readInt();
47         this.name = in.readString();
48     }
49 
50     public static final Parcelable.Creator<Dog> CREATOR = new Parcelable.Creator<Dog>() {
51         public Dog createFromParcel(Parcel source) {
52             return new Dog(source);
53         }
54 
55         public Dog[] newArray(int size) {
56             return new Dog[size];
57         }
58     };
59 }
View Code

然後寫一個介面IDogManager

 1 package com.example.administrator.writebindercodeexample;
 2 
 3 import android.os.IBinder;
 4 import android.os.IInterface;
 5 import android.os.RemoteException;
 6 
 7 import java.util.List;
 8 
 9 /**
10  * Created by Administrator on 2016/1/27.
11  */
12 public interface IDogManager extends IInterface {
13 
14     static final String DESCRIPTOR = "com.example.administrator.writebindercodeexample.IDogManager";
15     static final int TRANSACTION_getDogList = IBinder.FIRST_CALL_TRANSACTION + 0;
16     static final int TRANSACTION_addDog = IBinder.FIRST_CALL_TRANSACTION + 1;
17 
18     public List<Dog> getDogList() throws RemoteException;
19 
20     public void addDog(Dog dog) throws RemoteException;
21 
22 }

然後寫我們的binder,注意我們的binder 我這裡是寫的抽象類,因為你寫成實體類的話 就必須要實現IDogManger裡的2個方法 ,然而為了結構清晰 我們並不準備把binder 放在service裡 實現。

所以這裡binder 我們還是用抽象類來做,然後在service裡 實現 getDogList和addDog方法即可。

  1 package com.example.administrator.writebindercodeexample;
  2 
  3 import android.os.Binder;
  4 import android.os.IBinder;
  5 import android.os.Parcel;
  6 import android.os.RemoteException;
  7 
  8 /**
  9  * Created by Administrator on 2016/1/27.
 10  */
 11 public abstract class DogManagerImpl extends Binder implements IDogManager {
 12 
 13     public DogManagerImpl() {
 14         this.attachInterface(this, DESCRIPTOR);
 15     }
 16 
 17     public static com.example.administrator.writebindercodeexample.IDogManager asInterface(android.os.IBinder obj) {
 18         if ((obj == null)) {
 19             return null;
 20         }
 21         android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
 22         //如果是同1個程式,也就是說程式內通訊的話 我們就返回括號內裡的物件
 23         if (((iin != null) && (iin instanceof com.example.administrator.writebindercodeexample.IDogManager))) {
 24             return ((com.example.administrator.writebindercodeexample.IDogManager) iin);
 25         }
 26         //如果不是同一程式,是2個程式之間相互通訊,那我們就得返回這個Stub.Proxy 看上去叫Stub 代理的物件了
 27         return new com.example.administrator.writebindercodeexample.DogManagerImpl.Proxy(obj);
 28     }
 29 
 30 
 31     @Override
 32     public IBinder asBinder() {
 33         return this;
 34     }
 35 
 36     @Override
 37     protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
 38         switch (code) {
 39             case INTERFACE_TRANSACTION: {
 40                 reply.writeString(DESCRIPTOR);
 41                 return true;
 42             }
 43             case TRANSACTION_getDogList: {
 44                 data.enforceInterface(DESCRIPTOR);
 45                 java.util.List<com.example.administrator.writebindercodeexample.Dog> _result = this.getDogList();
 46                 reply.writeNoException();
 47                 reply.writeTypedList(_result);
 48                 return true;
 49             }
 50             case TRANSACTION_addDog: {
 51                 data.enforceInterface(DESCRIPTOR);
 52                 com.example.administrator.writebindercodeexample.Dog _arg0;
 53                 if ((0 != data.readInt())) {
 54                     _arg0 = com.example.administrator.writebindercodeexample.Dog.CREATOR.createFromParcel(data);
 55                 } else {
 56                     _arg0 = null;
 57                 }
 58                 this.addDog(_arg0);
 59                 reply.writeNoException();
 60                 return true;
 61             }
 62         }
 63         return super.onTransact(code, data, reply, flags);
 64     }
 65 
 66     private static class Proxy extends DogManagerImpl {
 67         private android.os.IBinder mRemote;
 68 
 69         Proxy(android.os.IBinder remote) {
 70             mRemote = remote;
 71         }
 72 
 73         @Override
 74         public android.os.IBinder asBinder() {
 75             return mRemote;
 76         }
 77 
 78         public java.lang.String getInterfaceDescriptor() {
 79             return DESCRIPTOR;
 80         }
 81 
 82         @Override
 83         public java.util.List<com.example.administrator.writebindercodeexample.Dog> getDogList() throws android.os.RemoteException {
 84             android.os.Parcel _data = android.os.Parcel.obtain();
 85             android.os.Parcel _reply = android.os.Parcel.obtain();
 86             java.util.List<com.example.administrator.writebindercodeexample.Dog> _result;
 87             try {
 88                 _data.writeInterfaceToken(DESCRIPTOR);
 89                 mRemote.transact(DogManagerImpl.TRANSACTION_getDogList, _data, _reply, 0);
 90                 _reply.readException();
 91                 _result = _reply.createTypedArrayList(com.example.administrator.writebindercodeexample.Dog.CREATOR);
 92             } finally {
 93                 _reply.recycle();
 94                 _data.recycle();
 95             }
 96             return _result;
 97         }
 98 
 99         @Override
100         public void addDog(com.example.administrator.writebindercodeexample.Dog dog) throws android.os.RemoteException {
101             android.os.Parcel _data = android.os.Parcel.obtain();
102             android.os.Parcel _reply = android.os.Parcel.obtain();
103             try {
104                 _data.writeInterfaceToken(DESCRIPTOR);
105                 if ((dog != null)) {
106                     _data.writeInt(1);
107                     dog.writeToParcel(_data, 0);
108                 } else {
109                     _data.writeInt(0);
110                 }
111                 mRemote.transact(DogManagerImpl.TRANSACTION_addDog, _data, _reply, 0);
112                 _reply.readException();
113             } finally {
114                 _reply.recycle();
115                 _data.recycle();
116             }
117         }
118     }
119 
120 }
View Code

 

到這,我們的手寫binder 就完成了,然後看看 service 以及客戶端 怎麼呼叫。

先看service:

 1 package com.example.administrator.writebindercodeexample;
 2 
 3 import android.app.Service;
 4 import android.content.Intent;
 5 import android.os.IBinder;
 6 import android.os.RemoteException;
 7 import android.util.Log;
 8 
 9 import java.util.ArrayList;
10 import java.util.List;
11 
12 public class RemoteService extends Service {
13 
14     private List<Dog> mDogsList = new ArrayList<Dog>();
15 
16     private final DogManagerImpl mBinder = new DogManagerImpl() {
17         @Override
18         public List<Dog> getDogList() throws RemoteException {
19             return mDogsList;
20         }
21 
22         @Override
23         public void addDog(Dog dog) throws RemoteException {
24             mDogsList.add(dog);
25         }
26     };
27 
28     @Override
29     public IBinder onBind(Intent intent) {
30         return mBinder;
31     }
32 }

然後看看 啟動如何在客戶端bind 這個service:

 1 private IDogManager mService;
 2 
 3     private ServiceConnection sc = new ServiceConnection() {
 4         @Override
 5         public void onServiceConnected(ComponentName name, IBinder service) {
 6             mService = DogManagerImpl.asInterface(service);
 7 
 8         }
 9 
10         @Override
11         public void onServiceDisconnected(ComponentName name) {
12             mService = null;
13         }
14     };

 

到這 就基本寫完了,手寫binder的好處就是 你可以自己在binder方法裡 寫一些log,能夠更加深刻的認識到 Binder 作為 程式間通訊 媒介的重要作用以及原理。

熟悉以後,還是用aidl 的方法 自動生成程式碼 最好。

 

相關文章