關於Binder,我就不解釋的太多了,網上一搜資料一堆,但是估計還是很多人理解的有困難。今天就教你如何從 app層面來理解好Binder。
其實就從我們普通app開發者的角度來看,僅僅對於android應用層的話,Binder就是客戶端和服務端進行通訊的媒介。
AIDL就是我們理解Binder 最好的事例。
我們都知道 我們寫好aidl 檔案以後,開發工具 會自動幫我們生成好程式碼。實際上 我們最終apk裡面 是隻有這些程式碼的,我們寫的aidl檔案
是不會被打包進去的,也就是說aidl檔案 實際上 就是我們用來 生成 實際binder程式碼用的。所以 我們只要能夠分析好,ide自動幫我們生成的
程式碼,就可以自己手寫binder,從而在app層面上真正理解binder的用法和含義 以及原理。
首先我先來定義一個實體類:Person.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
package com.example.administrator.writebindercodeexample; import android.os.Parcel; import android.os.Parcelable; /** * Created by Administrator on 2016/1/27. */ public class Person implements Parcelable { private String name; public void setName(String name) { this.name = name; } public void setGender(int gender) { this.gender = gender; } public int getGender() { return gender; } public String getName() { return name; } private int gender; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(this.name); dest.writeInt(this.gender); } public Person() { } protected Person(Parcel in) { this.name = in.readString(); this.gender = in.readInt(); } public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() { public Person createFromParcel(Parcel source) { return new Person(source); } public Person[] newArray(int size) { return new Person[size]; } }; } |
注意看 我們這個person 類 是實現了android自帶的序列化介面的,所以 如果你要在aidl裡使用這個類,那你必須要額外在aidl裡生命下 這個類。
1 2 3 4 5 |
// Person.aidl.aidl package com.example.administrator.writebindercodeexample; // Declare any non-default types here with import statements parcelable Person; |
1 2 3 4 5 6 7 8 9 10 |
// IPersonManager.aidl package com.example.administrator.writebindercodeexample; // Declare any non-default types here with import statements import com.example.administrator.writebindercodeexample.Person; interface IPersonManager { List<Person> getPersonList(); //關於這個引數in 其實你不加也是可以編譯通過的,這裡我就先加一下 具體引數的意義 以後會說 void addPerson(in Person person); } |
好,然後給你們看一下 檔案結構:
好 這裡就是一個典型的 應用aidl 技術的 一個例子,我們現在 讓studio 編譯這個project,然後看看生成的binder程式碼。 把這份binder程式碼 分析好了,我們以後就可以不借助ide 來自己手寫binder了。
我們來看看 生成的程式碼在哪裡:
最後我們來看一下 這個生成的程式碼 是啥樣的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
/* * This file is auto-generated. DO NOT MODIFY. * Original file: C:\\Users\\Administrator\\WriteBinderCodeExample\\app\\src\\main\\aidl\\com\\example\\administrator\\writebindercodeexample\\IPersonManager.aidl */ package com.example.administrator.writebindercodeexample; public interface IPersonManager extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.example.administrator.writebindercodeexample.IPersonManager { private static final java.lang.String DESCRIPTOR = "com.example.administrator.writebindercodeexample.IPersonManager"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.example.administrator.writebindercodeexample.IPersonManager interface, * generating a proxy if needed. */ public static com.example.administrator.writebindercodeexample.IPersonManager asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.example.administrator.writebindercodeexample.IPersonManager))) { return ((com.example.administrator.writebindercodeexample.IPersonManager)iin); } return new com.example.administrator.writebindercodeexample.IPersonManager.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_getPersonList: { data.enforceInterface(DESCRIPTOR); java.util.List<com.example.administrator.writebindercodeexample.Person> _result = this.getPersonList(); reply.writeNoException(); reply.writeTypedList(_result); return true; } case TRANSACTION_addPerson: { data.enforceInterface(DESCRIPTOR); com.example.administrator.writebindercodeexample.Person _arg0; if ((0!=data.readInt())) { _arg0 = com.example.administrator.writebindercodeexample.Person.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addPerson(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.example.administrator.writebindercodeexample.IPersonManager { 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.example.administrator.writebindercodeexample.Person> getPersonList() 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.administrator.writebindercodeexample.Person> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.example.administrator.writebindercodeexample.Person.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } //關於這個引數in 其實你不加也是可以編譯通過的,這裡我就先加一下 具體引數的意義 以後會說 @Override public void addPerson(com.example.administrator.writebindercodeexample.Person person) 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 ((person!=null)) { _data.writeInt(1); person.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } public java.util.List<com.example.administrator.writebindercodeexample.Person> getPersonList() throws android.os.RemoteException; //關於這個引數in 其實你不加也是可以編譯通過的,這裡我就先加一下 具體引數的意義 以後會說 public void addPerson(com.example.administrator.writebindercodeexample.Person person) throws android.os.RemoteException; } |
看上去呢,雜亂無章, 但其實也就是100多行,所以 我調整了一下 這個程式碼的順序 ,你們可以看的更清楚,同時也增加了註釋:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
package com.example.administrator.aidlmessagetest; //為了讓大家看的更清楚 我把生成的binder程式碼 給拷貝到另外一個工程下面了,並且用ide 給他format //所以包名和我們一開始前面的程式碼都不一樣,大家理解意思就行。 //從前面幾行就能看出來 生成的程式碼是一個 interface ,只不過這個interface是 android.os.IInterface 的子類! public interface IPersonManager extends android.os.IInterface { //並且這個介面裡 有一個靜態的抽象類Stub(注意這個名字是固定的 永遠都是Stub 不會是其他) //並且這個Stub是Binder的子類,並且實現了IPersonManager 這個介面 public static abstract class Stub extends android.os.Binder implements com.example.administrator.aidlmessagetest.IPersonManager { //這個東西就是唯一的binder標示 可以看到就是IPersonManager的全路徑名 private static final java.lang.String DESCRIPTOR = "com.example.administrator.aidlmessagetest.IPersonManager"; /** * 這個就是Stub的構造方法,回顧一下 我們如果寫好aidl檔案以後 寫的service裡面 是怎麼寫的? * * private final IPersonManager.Stub mBinder = new IPersonManager.Stub() {} * 我們都是這麼寫的 對吧~~所以想想我們的service裡面的程式碼 就能輔助理解 這裡的程式碼了 */ public Stub() { this.attachInterface(this, DESCRIPTOR); } //這個方法 其實就做了一件事,如果是同一個程式,那麼就返回Stub物件本身 //如果不是同一個程式,就返回Stub.Proxy這個代理物件了 public static com.example.administrator.aidlmessagetest.IPersonManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); //如果是同1個程式,也就是說程式內通訊的話 我們就返回括號內裡的物件 if (((iin != null) && (iin instanceof com.example.administrator.aidlmessagetest.IPersonManager))) { return ((com.example.administrator.aidlmessagetest.IPersonManager) iin); } //如果不是同一程式,是2個程式之間相互通訊,那我們就得返回這個Stub.Proxy 看上去叫Stub 代理的物件了 return new com.example.administrator.aidlmessagetest.IPersonManager.Stub.Proxy(obj); } //返回當前物件 @Override public android.os.IBinder asBinder() { return this; } //只有在多程式通訊的時候 才會呼叫這個方法 ,同一個程式是不會呼叫的。 //首先 我們要明白 這個方法 一般情況下 都是返回true的,也只有返回true的時候才有意義,如果返回false了 就代表這個方法執行失敗, //所以我們通常是用這個方法來做許可權認證的,其實也很好理解,既然是多程式通訊,那麼我們服務端的程式當然不希望誰都能過來呼叫 //所以許可權認證是必須的,關於許可權認證的程式碼 以後我再講 先略過。 //除此之外 ,onTransact 這個方法 就是執行在Binder執行緒池中的,一般就是客戶端發起請求,然後android底層程式碼把這個客戶端發起的 //請求 封裝成3個引數 來呼叫這個onTransact方法,第一個引數code 就代表客戶端想要呼叫服務端 方法的 標誌位。 //其實也很好理解 服務端可能有n個方法 每個方法 都有一個對應的int值來代表,這個code就是這個int值,用來標示客戶端想呼叫的服務端的方法 //data就是方法引數,reply就是方法返回值。都很好理解 //其實隱藏了很重要的一點,這個方法既然是執行在binder執行緒池中的,所以在這個方法裡面呼叫的伺服器方法也是執行在Binder執行緒池中的, //所以我們要記得 如果你的服務端程式 有可能和多個客戶端相聯的話,你方法裡使用的那些引數 必須要是支援非同步的,否則的話 //值就會錯亂了!這點一定要記住!結論就是Binder方法 一定要是同步方法!!!!!! @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_getPersonList: { data.enforceInterface(DESCRIPTOR); java.util.List<com.example.administrator.aidlmessagetest.Person> _result = this.getPersonList(); reply.writeNoException(); reply.writeTypedList(_result); return true; } case TRANSACTION_addPerson: { data.enforceInterface(DESCRIPTOR); com.example.administrator.aidlmessagetest.Person _arg0; if ((0 != data.readInt())) { _arg0 = com.example.administrator.aidlmessagetest.Person.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addPerson(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } //注意這裡的Proxy 這個類名也是不變的,從前文我們知道 只有在多程式通訊的情況下 才會返回這個代理的物件 private static class Proxy implements com.example.administrator.aidlmessagetest.IPersonManager { 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; } //這裡我們一共有2個方法 一個getPersonList 一個addPerson 我們就分析一個方法就可以了 //並且要知道 這2個方法執行在客戶端!!!!!!!!!!!!!!!! //首先就是建立了3個物件_data 輸入物件,_reply輸出物件,_result返回值物件 //然後把引數資訊 寫入到_data裡,接著就呼叫了transact這個方法 來傳送rpc請求,然後接著 //當前執行緒掛起, 服務端的onTransace方法才被呼叫,呼叫結束以後 當前執行緒繼續執行,直到 //從_reply中取出rpc的返回結果 然後返回_reply的資料 //所以這裡我們就要注意了,客戶端發起呼叫遠端請求時,當前客戶端的執行緒就會被掛起了, //所以如果一個遠端方法 很耗時,我們客戶端就一定不能在ui main執行緒裡在發起這個rpc請求,不然就anr了。 @Override public java.util.List<com.example.administrator.aidlmessagetest.Person> getPersonList() 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.administrator.aidlmessagetest.Person> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.example.administrator.aidlmessagetest.Person.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } //你看自動生成binder程式碼的時候 連你的註釋也一起拷貝過來了。。。。。是不是很有趣 //關於這個引數in 其實你不加也是可以編譯通過的,這裡我就先加一下 具體引數的意義 以後會說 @Override public void addPerson(com.example.administrator.aidlmessagetest.Person person) 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 ((person != null)) { _data.writeInt(1); person.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } public java.util.List<com.example.administrator.aidlmessagetest.Person> getPersonList() throws android.os.RemoteException; //關於這個引數in 其實你不加也是可以編譯通過的,這裡我就先加一下 具體引數的意義 以後會說 public void addPerson(com.example.administrator.aidlmessagetest.Person person) throws android.os.RemoteException; } |
到這裡 相信大家 至少在應用層上面,就對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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
package com.example.administrator.writebindercodeexample; import android.os.Parcel; import android.os.Parcelable; /** * Created by Administrator on 2016/1/27. */ public class Dog implements Parcelable { public int getGender() { return gender; } public String getName() { return name; } public void setGender(int gender) { this.gender = gender; } public void setName(String name) { this.name = name; } private int gender; private String name; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(this.gender); dest.writeString(this.name); } public Dog() { } protected Dog(Parcel in) { this.gender = in.readInt(); this.name = in.readString(); } public static final Parcelable.Creator<Dog> CREATOR = new Parcelable.Creator<Dog>() { public Dog createFromParcel(Parcel source) { return new Dog(source); } public Dog[] newArray(int size) { return new Dog[size]; } }; } |
然後寫一個介面IDogManager
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package com.example.administrator.writebindercodeexample; import android.os.IBinder; import android.os.IInterface; import android.os.RemoteException; import java.util.List; /** * Created by Administrator on 2016/1/27. */ public interface IDogManager extends IInterface { static final String DESCRIPTOR = "com.example.administrator.writebindercodeexample.IDogManager"; static final int TRANSACTION_getDogList = IBinder.FIRST_CALL_TRANSACTION + 0; static final int TRANSACTION_addDog = IBinder.FIRST_CALL_TRANSACTION + 1; public List<Dog> getDogList() throws RemoteException; public void addDog(Dog dog) throws RemoteException; } |
然後寫我們的binder,注意我們的binder 我這裡是寫的抽象類,因為你寫成實體類的話 就必須要實現IDogManger裡的2個方法 ,然而為了結構清晰 我們並不準備把binder 放在service裡 實現。
所以這裡binder 我們還是用抽象類來做,然後在service裡 實現 getDogList和addDog方法即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
package com.example.administrator.writebindercodeexample; import android.os.Binder; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; /** * Created by Administrator on 2016/1/27. */ public abstract class DogManagerImpl extends Binder implements IDogManager { public DogManagerImpl() { this.attachInterface(this, DESCRIPTOR); } public static com.example.administrator.writebindercodeexample.IDogManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); //如果是同1個程式,也就是說程式內通訊的話 我們就返回括號內裡的物件 if (((iin != null) && (iin instanceof com.example.administrator.writebindercodeexample.IDogManager))) { return ((com.example.administrator.writebindercodeexample.IDogManager) iin); } //如果不是同一程式,是2個程式之間相互通訊,那我們就得返回這個Stub.Proxy 看上去叫Stub 代理的物件了 return new com.example.administrator.writebindercodeexample.DogManagerImpl.Proxy(obj); } @Override public IBinder asBinder() { return this; } @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_getDogList: { data.enforceInterface(DESCRIPTOR); java.util.List<com.example.administrator.writebindercodeexample.Dog> _result = this.getDogList(); reply.writeNoException(); reply.writeTypedList(_result); return true; } case TRANSACTION_addDog: { data.enforceInterface(DESCRIPTOR); com.example.administrator.writebindercodeexample.Dog _arg0; if ((0 != data.readInt())) { _arg0 = com.example.administrator.writebindercodeexample.Dog.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addDog(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy extends DogManagerImpl { 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.example.administrator.writebindercodeexample.Dog> getDogList() 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.administrator.writebindercodeexample.Dog> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(DogManagerImpl.TRANSACTION_getDogList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.example.administrator.writebindercodeexample.Dog.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void addDog(com.example.administrator.writebindercodeexample.Dog dog) 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 ((dog != null)) { _data.writeInt(1); dog.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(DogManagerImpl.TRANSACTION_addDog, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } } |
到這,我們的手寫binder 就完成了,然後看看 service 以及客戶端 怎麼呼叫。
先看service:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package com.example.administrator.writebindercodeexample; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import java.util.ArrayList; import java.util.List; public class RemoteService extends Service { private List<Dog> mDogsList = new ArrayList<Dog>(); private final DogManagerImpl mBinder = new DogManagerImpl() { @Override public List<Dog> getDogList() throws RemoteException { return mDogsList; } @Override public void addDog(Dog dog) throws RemoteException { mDogsList.add(dog); } }; @Override public IBinder onBind(Intent intent) { return mBinder; } } |
然後看看 啟動如何在客戶端bind 這個service:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
private IDogManager mService; private ServiceConnection sc = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService = DogManagerImpl.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { mService = null; } }; |
到這 就基本寫完了,手寫binder的好處就是 你可以自己在binder方法裡 寫一些log,能夠更加深刻的認識到 Binder 作為 程式間通訊 媒介的重要作用以及原理。
熟悉以後,還是用aidl 的方法 自動生成程式碼 最好。