android aidl通信 RemoteCallbackList客戶端注冊回調


RemoteCallbackList

聲明

public class RemoteCallbackList<E extends IInterface>

情況

AIDL中客戶端向服務端注冊一個回調方法時,服務端要考慮客戶端是否意外退出(客戶端因為錯誤應用Crash,或者被Kill掉了),服務端還不知道去回調客戶端,出現錯誤

客戶端和服務端進程狀態

在進程間通信過程中,很可能出現一個進程死亡的情況。如果這時活着的一方不知道另一方已經死了就會出現問題。那我們如何在A進程中獲取B進程的存活狀態呢?

android肯定給我們提供了解決方式,那就是BinderlinkToDeathunlinkToDeath方法,linkToDeath方法需要傳入一個DeathRecipient對象,DeathRecipient類里面有個binderDied方法,binder對象的所在進程死亡,binderDied方法就會被執行,我們就可以在binderDied方法里面做一些異常處理,釋放資源等操作了

 

參考:http://www.jianshu.com/p/ce3944e5ff11

 

Android SDK提供一個封裝好的對象:RemoteCallbackList,幫我自動處理了Link-To-Death的問題,這就幫我們剩下了很多代碼了。

    ...

    mClientCallBack = IRemoteCallBack.Stub.asInterface(callback);

    if (mClientDeathHandler == null) {

          mClientDeathHandler = new ClientDeathRecipient();

    }

    mClientCallBack.asBinder().linkToDeath(new ClientDeathRecipient(), 0);

    ...

private class ClientDeathRecipient implements IBinder.DeathRecipient {

 

        @Override

        public void binderDied() {

            mCallbackList.unregister(mClientCallBack);

            mClientCallBack = null;

            Logger.d(TAG,"client  is died");

        }

    }

 

上面是在server端對client的回調接口的binder對象設置的DeathRecipient。在client死亡時,解注冊client的回調,並且置空。

有注冊回調就肯定有解注冊,但是client端與server不在一個進程,server是無法得知client解注冊時傳入的回調接口是哪一個(client調用解注冊時,是通過binder傳輸到server端,所以解注冊時的回調接口是新創建的,而不是注冊時的回調接口)。為了解決這個問題,android提供了RemoteCallbackList這個類來專門管理remote回調的注冊與解注冊。具體參考RemoteCallbackList的源碼

Messenger與AIDL的異同

其實Messenger的底層也是用AIDL實現的,但用起來還是有些不同的,這里總結了幾點區別:

1. Messenger本質也是AIDL,只是進行了封裝,開發的時候不用再寫.aidl文件。

結合我自身的使用,因為不用去寫.aidl文件,相比起來,Messenger使用起來十分簡單。但前面也說了,Messenger本質上也是AIDL,故在底層進程間通信這一塊,兩者的效率應該是一樣的。

2. service端,Messenger處理client端的請求是單線程的,而AIDL是多線程的。

使用AIDL的時候,service端每收到一個client端的請求時,就在BInder線程池中取一個線程去執行相應的操作。而Messengerservice收到的請求是放在HandlerMessageQueue里面,Handler大家都用過,它需要綁定一個Thread,然后不斷poll message執行相關操作,這個過程是同步執行的。

3. client的方法,使用AIDL獲取返回值是同步的,而Messenger是異步的。

Messenger只提供了一個方法進行進程間通信,就是send(Message msg)方法,發送的是一個Message,沒有返回值,要拿到返回值,需要把clientMessenger作為msg.replyTo參數傳遞過去,service端處理完之后,在調用客戶端的Messengersend(Message msg)方法把返回值傳遞回client,這個過程是異步的,而AIDL你可以自己指定方法,指定返回值,它獲取返回值是同步的(如果沒有用oneway修飾方法的話)。

 

總的來說,AIDL靈活性更高,如果需要IPC通信的地方比較多,還是更推薦自定義AIDL一點。

aidl

aidl中有onway,in,out,inout關鍵字修飾

oneway

正常情況下Client調用AIDL接口方法時會阻塞,直到Server進程中該方法被執行完。oneway可以修飾AIDL文件里的方法,oneway修飾的方法在用戶請求相應功能時不需要等待響應可直接調用返回,非阻塞效果,該關鍵字可以用來聲明接口或者聲明方法,如果接口聲明中用到了oneway關鍵字,則該接口聲明的所有方法都采用oneway方式。(注意,如果clientServer在同一進程中,oneway修飾的方法還是會阻塞),oneway只能針對某一個接口,不能直接定義方法。 方法必須是void類型的返回值類型

in

非基本數據類型和string的參數類型必須加參數修飾符,in的意思是只輸入,既最終server端執行完后不會影響到參數對象

out

與in相反,out修飾的參數只能由server寫入並傳遞到client,而client傳入的值並不會傳遞到server,使用out修飾,如果參數是自定義了類型,必須實現parcelable接口,並且實現public void readFromParcel(Parcel in)方法

inout

inout修飾的參數,既可以從client傳遞到server,也可以server傳遞到client,使用out修飾,如果參數是自定義了類型,必須實現Parcelable接口,並且實現public void readFromParcel(Parcel in)方法

 

如果aidl中使用了自定義類型,必須實現Parcelable接口,並新建一個和自定義類型名相同的aidl,內容就是parcelable 接口名稱


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM