最近在複習Android跨進程調用,整理了一下自己對Binder的一些理解,希望能對大家也有所幫助,如有錯誤歡迎指正~
爲了加深理解,希望看完後能自己操練驗證一下,要不真的很容易眼高手低哦
ps:不想細看,可以只看裏面的3張圖片即可~ ^_^
好了,迴歸主題,我們現在寫個AIDL文件:
#IController.aidl
// Declare any non-default types here with import statements
interface IController {
void showMessage(String msg);
}
我們先來看一下默認生成文件的註釋:
意思是說:如果不是默認類型,需要進行相應的import,類似java導包一樣
那默認類型有哪些呢?
int、long、boolean、float、double、String、in/out/inout List
而Parcelable的實現類、aidl接口類
這個是需要進行import的
添加完AIDL文件後,我們編譯一下,然後找到IController.java類,這個類是系統幫我們把AIDL文件轉化爲一個Java類,便於我們進行使用,當然我們自己也可以寫~~
我們來看一下這個類的代碼:
public interface IController extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.example.yukai.test.IController {
private static final java.lang.String DESCRIPTOR = "com.example.yukai.test.IController";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.yukai.test.IController interface,
* generating a proxy if needed.
*/
public static com.example.yukai.test.IController asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.yukai.test.IController))) {
return ((com.example.yukai.test.IController) iin);
}
return new com.example.yukai.test.IController.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_showMessage: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
this.showMessage(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.yukai.test.IController {
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 showMessage(java.lang.String msg) 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.writeString(msg);
mRemote.transact(Stub.TRANSACTION_showMessage, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_showMessage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void showMessage(java.lang.String msg) throws android.os.RemoteException;
}
這是格式化之後的樣子,我對這個類做了一個初步的結構圖繪製如下:
可以比較明顯的看到類的嵌套結構,一個接口類:IController,裏面包含了接口方法(即我們聲明的那個方法)和 一個Stub類:
爲屏蔽客戶調用遠程主機上的對象,必須提供某種方式來模擬本地對象,這種本地對象稱爲存根(stub),存根負責接收本地方法調用,並將它們委派給各自的具體實現對象
我覺得上面這個解釋還可以,基本表達了Stub的作用~
看完上面的圖,覺得還是有點亂,既然是static class 靜態內部類,那其實我們可以把裏面的class抽離出來,作爲一個新的文件,參考下圖結構:
其中IController、Stub、Proxy類可以看成三個獨立的類/接口
繼承關係圖也可以很清晰的看出來,那這三者是如何相互合作使用的呢?下面這個圖可以很好的表達出具體的Activity與本地/遠程Service交互邏輯和對應上面幾個類的使用:
圖注:
左面的Service是跟Activity處於同一個進程下的
右面的Service是跟Activity非同一個進程下的,可能是remote或其他
“所以測試的時候需要分別測這兩種情況,有process:remote和什麼都不寫默認進程的。”
1.與當前進程的Service交互
在bind Service後,onServiceConnected會返回對應的binder對象,我們可以調試發現這個對象跟Service裏面的binder對象其實是 同一個對象,因此我們可以直接轉成我們Service的Binder,然後直接調用;當然如果用的是AIDL的方式,我們可以調用Stub的靜態方法:asInterface,可以做相應的轉化。
說到這裏,我們還需要看一下這個asInterface方法實現,先只看一半:
public static com.test.IController asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.test.IController))) {
return ((com.test.IController) iin);
}
--------other return-------
}
關鍵在這裏:
queryLocalInterface,查看源碼可以發現,裏面判斷的是參數的IBinder對象的描述符是否是DESCRIPTOR,如果是,就會返回IController這個owner對象,所以就可以進行相應的強轉並返回。
那remote返回什麼呢?那看一下第二條吧~
2.與remote進程的Service交互
我們來看一下上面省略的那行代碼:
return new com.test.IController.Stub.Proxy(obj);
看到這裏原來返回的是個Proxy對象,那個obj會是什麼呢?通過調試發現類名是BinderProxy對象,這個類我們的SDK裏看不到,但是我們能在源碼裏找到,發現這個類是也是繼承IBinder類,這個類負責與底層binder進行傳遞數據,然後會調用遠程的Stub.onTransact,進行真實的Service方法調用。參照圖片可以更好的理解一下~
3. 對應的Service與Activity進行交互
我們可以通過RemoteCallbackList這個類進行相關注冊並進行回調,這個實現起來像是Activity是服務端,Service是客戶端,大家可以實現一下看看~ 發現Stub是在Activity裏新建並傳遞給Service端,由Service進行相應回調。當然還可以通過其他方式,比如廣播(LocalBroadcast)也是可以的~~
就先寫到這,如果有不對的地方,歡迎指正,多謝~~