IPC 簡介
IPC 是 Inter-Process Communication 的縮寫,含義為進程間通信或跨進程通信,是指兩個進程之間進行數據交換的過程。
IPC 的場景
- 一個應用由于自身需要,采用多進程方式實現。例如:某個模塊需要運行在單獨的進程中。
- 兩個應用交換數據。
應用使用多進程會導致的問題
- 靜態成員和單例模式失效
Android 為每個進程分配獨立的虛擬機,不同的虛擬機分配了不同的內存空間,一個進程中對靜態變量的修改只對本進程有效。 - 線程同步機制失效
不論鎖對象還是全局類都無法保證線程同步,因為在不同進程中鎖的不是同一個對象。 - SharedPreferences 的可靠性降低
兩個進程并發寫 SharedPreferences ,可能會發生數據丟失的情況。 - Application 會多次創建
每個進程運行在獨立的虛擬機上,會創建獨立的 Application 實例。
IPC 方式
1.Bundle
四大組件之三 Activity、Service 和 BroadcastReceiver 均支持在 Intent 中傳遞 Bundle 數據。
當我們需要向其他進程傳輸數據時,可以通過 Intent 將需要傳遞的數據傳遞給目標進程的組件。
要求:需要傳遞的數據能夠被序列化,例如基本類型、實現了 Parcelable 或 Serializable 接口的類的實例、Android 支持的特殊對象。
Bundle 不支持的類型無法通過這種方式進行進程間通信。
2. 文件共享
兩個進程通過讀寫同一個文件來交換數據。
除了可以交換文本信息外,也可以傳遞序列化的對象。
適用場景:對數據同步要求不高的進程間通信,需要妥善處理并發讀寫問題。
SharedPreferences 是使用 XML 文件來存儲鍵值對的,但是 Android 系統會在內存中對它進行緩存,在多進程模式下,系統對它的讀寫就不再可靠。當面對高并發的讀寫訪問時,SharedPreferences 很可能會丟失數據。所以,不建議在進程間通信中使用 SharedPreferences,可以考慮使用 MMKV。
MMKV for Android 多進程訪問支持的設計與實現
3. Messenger
Messenger 信使,它可以在不同進程間傳遞 Message 對象。在 Message 對象中放入需要傳遞的數據,就可以輕松地實現進程間傳遞數據的目標。
Messenger 是一種輕量級的 IPC 方案,底層實現是 AIDL 。
Message 中能使用的載體有 what(int)、arg1(int)、arg2(int)、Bundle 和 replyTo(Messenger) 。
Messenger 的使用
- 服務端進程
- 創建一個 Service 來處理客戶端的連接請求
- 創建一個 Handler,并通過它來創建一個 Messenger 對象
- 在 Service 的 onBind 中返回 Messenger 對象底層的 IBinder
- 客戶端進程
- 綁定服務端的 Service,用服務端返回的 IBinder 對象創建一個 Messenger
- 用 Messenger 向服務端發送消息,消息的類型為 Message
通過以上操作,就可以完成客戶端向服務端的單向通信了。如需支持服務端響應客戶端:
- 客戶端進程
- 創建一個 Handler,并通過它創建一個新的 Messenger 對象
- 將新創建的 Messenger 對象通過 Message 的 replyTo 參數傳遞給服務端進程
- 服務端進程
- 取出客戶端通過 replyTo 參數的傳遞過來的 Messenger 對象
- 使用 Messenger 對象回應客戶端
4. AIDL
使用 AIDL 進行進程間通信的流程
- 服務端
- 創建一個 Service,用來監聽客戶端的連接請求
- 創建一個 AIDL 文件,用來聲明暴露給客戶端的接口
- 在 Service 中實現 AIDL 文件中聲明的接口
- 客戶端
- 綁定服務端的 Service
- 將服務端返回的 Binder 對象轉成 AIDL 接口所屬的類型
- 調用 AIDL 中的方法
AIDL 支持的數據類型
- 基本數據類型
- String 和 CharSequence
- ArrayList,集合中的每個元素必須被 AIDL 支持
- HashMap,集合中的每個元素必須被 AIDL 支持,包括 key 和 value
- Parcelable:所有實現了 Parcelable 接口的類
- AIDL:所有的 AIDL 接口
5. ContentProvider
ContentProvider 是 Android 提供的不同應用間數據共享的方式,底層實現是 Binder。
Android 系統預置了許多 ContentProvider,比如通訊錄信息、日程表信息等,要跨進程訪問這些信息,只需要通過 ContentResolver 的 query()、update()、insert() 和 delete() 方法即可。
ContentProvider 主要以表格的形式組織數據,和數據庫相似。它還支持文件文件數據,例如圖片、視頻等。Android 提供的 MediaStore 就是文件類型的 ContentProvider。
雖然 ContentProvider 的底層數據看起來很像一個 SQLite 數據庫,但是它對數據的存儲方法并沒有任何要求,我們既可以使用 SQLite 數據庫,也可以使用普通的文件,甚至可以采用內存中的一個對象來進行數據的存儲。
自定義 ContentProvider
- 繼承 ContentProvider 類,實現 6 個抽象方法:onCreate()、query()、update()、insert()、delete() 和 getType() 。
- 建立數據存儲系統,比較常用的使用 SQLite 數據庫。
- 注冊 ContentProvider,在 AndroidManifest 文件中聲明。
ContentProvider 的抽象方法
- onCreate() : ContentProvider 的初始化。
- getType() : 返回一個 Uri 請求所對應的 MIME 類型。
- query()、update()、insert() 和 delete(): 數據的增刪改查。
- 6 個方法均運行在 ContentProvider 的進程中,onCreate() 由系統回調并運行在主線程里,其他 5 個方法均由外界回調并運行在 Binder 線程池中。
6. Socket
Socket,套接字,是網絡通信中的概念。分為流式套接字和用戶數據報套接字兩種,分別對應網絡的傳輸控制層中的 TCP 和 UDP。
通過 Socket 不僅能實現進程間的通信,還可以實現設備間的通信,前提是通信的設備的 IP 地址互相可見。
IPC 方式比較
名稱 | 優點 | 缺點 | 適用場景 |
---|---|---|---|
Bundle | 簡單易用 | 只能傳輸 Bundle 支持的數據類型 | 四大組件間的進程間通信 |
文件共享 | 簡單易用 | 不適合高并發場景,不支持進程間的即時通信 | 無并發需求,交換簡單的數據,對實時性要求不高 |
AIDL | 支持一對多并發通信,支持實時通信 | 使用比較復雜,需要處理好線程同步 | 一對多通信,有 RPC 需求 |
Messenger | 支持一對多串行通信,支持實時通信 | 只能傳輸 Bundle 支持的數據類型,不能很好地處理高并發情形,不支持 RPC | 低并發的一對多通信,無 RPC 需求,或者有不需要返回結果的 RPC 需求 |
ContentProvider | 支持一對多并發數據共享,可通過 Call 方法擴展其他操作 | 主要提供數據源的 CRUD 操作 | 一對多的進程間的數據共享 |
Socket | 支持一對多并發實時通信,可以通過網絡傳輸字節流 | 使用比較復雜,不支持直接 RPC | 網絡數據交換 |
附
測試設備參數
- 型號:vivo Y66L
- 操作系統:Funtouch OS 3.0(Android 6.0.1)
參考資料
任玉剛.Android 開發藝術探索[M].電子工業出版社:北京,2015:35-121.