Android進程間通訊-AIDL實現原理

Android進程間通訊基於Proxy(代理)與Stub(樁或存根)的設計模式(如圖1-1所示)。其中,Proxy將特殊性接口轉換成通用性接口,Stub將通用性接口轉換成特殊性接口,兩者之間的數據轉換經過Parcel(打包)進行的,Proxy常做爲數據發送代理,經過Parcel將數據打包發送,Stub常做爲數據接收樁,解包並解析Parcel Data package。Android進程間通訊就是經過這樣的 「代理-樁」 的設計模式運做的。java

                                                           圖 1-1設計模式

關於Proxy與Stub注意:gradle

  1. Stub 跟 Proxy 是一對,俗稱「代理-樁」,通常用在遠程方法調用。
  2. Proxy 至關因而拿在手裏的遙控器,而 Stub 至關於長在電視機裏的遙控接收器,它們有着一一對應的接口方法,但操做的方向恰好相反。
  3. Proxy 的接口供客戶端程序調用,而後它內部會把信息包裝好,以某種方式(好比 RMI)傳遞給 Stub,然後者經過對應的接口做用於服務端系統,從而完成了「遠程調用」。
  4. 通常不一樣進程間通訊的時候都會用到這種模式。
  5. 關於Stub的asInterface(Binder), 能夠返回Stub或Stub.Proxy(若是客戶端和服務端在同一個進程下,那麼asInterface()將返回Stub對象自己,不然返回Stub.Proxy對象)。咱們都知道,Binder的工做機制客戶端,Binder,服務端組成的,客戶端和服務端都是經過Binder來交流的(Binder也是Android中一個java類)。AIDL生成的java代碼中,Stub類是繼承於Binder類的,也就是說Stub實例就是Binder實例。
  6. Stub和Stub.Proxy的區別:(1)若是在同一個進程下的話,那麼asInterface()將返回服務端的Stub對象自己,由於此時根本不須要跨進稱通訊,那麼直接調用Stub對象的接口就能夠了,返回的實現就是服務端的Stub實現,也就是根本沒有跨進程通訊;(2)若是不是同一個進程,那麼asInterface()返回是Stub.Proxy對象,該對象持有着遠程的Binder引用,由於如今須要跨進程通訊,因此若是調用Stub.Proxy的接口的話,那麼它們都將是IPC調用,它會經過調用transact方法去與服務端通訊。

關於AIDL定義以及實現流程圖:編碼

AIDL是一個縮寫,全稱是Android Interface Definition Language,也就是Android接口定義語言。咱們在寫完AIDL文件後,編譯器會幫咱們自動生成一個同名的 .java 文件(在gen相應目錄下)。在服務端和客戶端中也能夠照常使用這個 .java 類來進行跨進程通訊。spa

關於Proxy類幾個對象及方法(客戶端最終經過這個Proxy類與服務端進行通訊).net

    • 關於 _data_reply 對象:通常來講,咱們會將方法的傳參的數據存入_data 中,而將方法的返回值的數據存入 _reply 中—在沒涉及定向 tag 的狀況下。若是涉及了定向 tag ,狀況將會變得稍微複雜些,具體是怎麼回事請參見這篇博文:你真的理解AIDL中的in,out,inout麼?
    • 關於 Parcel :簡單的來講,Parcel 是一個用來存放和讀取數據的容器。咱們能夠用它來進行客戶端和服務端之間的數據傳輸,固然,它能傳輸的只能是可序列化的數據。具體 Parcel 的使用方法和相關原理能夠參見這篇文章:Android中Parcel的分析以及使用
    • 關於 transact() 方法:這是客戶端和服務端通訊的核心方法。調用這個方法以後,客戶端將會掛起當前線程,等候服務端執行完相關任務後通知並接收返回的 _reply 數據流。關於這個方法的傳參,這裏有兩點須要說明的地方: 
      • 方法 ID :transact() 方法的第一個參數是一個方法 ID ,這個是客戶端與服務端約定好的給方法的編碼,彼此一一對應。在AIDL文件轉化爲 .java 文件的時候,系統將會自動給AIDL文件裏面的每個方法自動分配一個方法 ID。
      • 第四個參數:transact() 方法的第四個參數是一個 int 值,它的做用是設置進行 IPC 的模式,爲 0 表示數據能夠雙向流通,即 _reply 流能夠正常的攜帶數據回來,若是爲 1 的話那麼數據將只能單向流通,從服務端回來的 _reply 流將不攜帶任何數據。 
        注:AIDL生成的 .java 文件的這個參數均爲 0。

關於客戶端通常的工做流程:線程

  • 1,生成 _data 和 _reply 數據流,並向 _data 中存入客戶端的數據。
  • 2,經過 transact() 方法將它們傳遞給服務端,並請求服務端調用指定方法。
  • 3,接收 _reply 數據流,並從中取出服務端傳回來的數據。

關於服務端的通常工做流程:設計

  • 1,獲取客戶端傳過來的數據,根據方法 ID 執行相應操做。
  • 2,將傳過來的數據取出來,調用本地寫好的對應方法。
  • 3,將須要回傳的數據寫入 reply 流,傳回客戶端。

關於Android中AIDL的簡單例子,參加以下Demo:代理

https://blog.csdn.net/jingwen3699/article/details/53400288對象

(注意:在Android Studio中,客戶端和服務端的AIDL接口文件所在的包未必相同,最好在gradle中配置路徑!)

 

其它參考連接:

https://blog.csdn.net/scnuxisan225/article/details/49970217 

https://blog.csdn.net/a910626/article/details/51173668

https://blog.csdn.net/luoyanglizi/article/details/52029091 (詳細原理來分析,good)

相關文章
相關標籤/搜索