IPC 簡介
IPC 是 Inter-Process Communication 的縮寫琴锭,含義為進程間通信或跨進程通信氢哮,是指兩個進程之間進行數(shù)據(jù)交換的過程缓待。
IPC 的場景
- 一個應(yīng)用由于自身需要编整,采用多進程方式實現(xiàn)缰儿。例如:某個模塊需要運行在單獨的進程中锦秒。
- 兩個應(yīng)用交換數(shù)據(jù)露泊。
應(yīng)用使用多進程會導(dǎo)致的問題
- 靜態(tài)成員和單例模式失效
Android 為每個進程分配獨立的虛擬機,不同的虛擬機分配了不同的內(nèi)存空間旅择,一個進程中對靜態(tài)變量的修改只對本進程有效惭笑。 - 線程同步機制失效
不論鎖對象還是全局類都無法保證線程同步,因為在不同進程中鎖的不是同一個對象。 - SharedPreferences 的可靠性降低
兩個進程并發(fā)寫 SharedPreferences 沉噩,可能會發(fā)生數(shù)據(jù)丟失的情況捺宗。 - Application 會多次創(chuàng)建
每個進程運行在獨立的虛擬機上,會創(chuàng)建獨立的 Application 實例川蒙。
IPC 方式
1.Bundle
四大組件之三 Activity蚜厉、Service 和 BroadcastReceiver 均支持在 Intent 中傳遞 Bundle 數(shù)據(jù)。
當我們需要向其他進程傳輸數(shù)據(jù)時畜眨,可以通過 Intent 將需要傳遞的數(shù)據(jù)傳遞給目標進程的組件昼牛。
要求:需要傳遞的數(shù)據(jù)能夠被序列化,例如基本類型康聂、實現(xiàn)了 Parcelable 或 Serializable 接口的類的實例贰健、Android 支持的特殊對象。
Bundle 不支持的類型無法通過這種方式進行進程間通信早抠。
2. 文件共享
兩個進程通過讀寫同一個文件來交換數(shù)據(jù)霎烙。
除了可以交換文本信息外撬讽,也可以傳遞序列化的對象蕊连。
適用場景:對數(shù)據(jù)同步要求不高的進程間通信,需要妥善處理并發(fā)讀寫問題游昼。
SharedPreferences 是使用 XML 文件來存儲鍵值對的甘苍,但是 Android 系統(tǒng)會在內(nèi)存中對它進行緩存,在多進程模式下烘豌,系統(tǒng)對它的讀寫就不再可靠载庭。當面對高并發(fā)的讀寫訪問時,SharedPreferences 很可能會丟失數(shù)據(jù)廊佩。所以囚聚,不建議在進程間通信中使用 SharedPreferences,可以考慮使用 MMKV标锄。
MMKV for Android 多進程訪問支持的設(shè)計與實現(xiàn)
3. Messenger
Messenger 信使顽铸,它可以在不同進程間傳遞 Message 對象。在 Message 對象中放入需要傳遞的數(shù)據(jù)料皇,就可以輕松地實現(xiàn)進程間傳遞數(shù)據(jù)的目標谓松。
Messenger 是一種輕量級的 IPC 方案,底層實現(xiàn)是 AIDL 践剂。
Message 中能使用的載體有 what(int)鬼譬、arg1(int)、arg2(int)逊脯、Bundle 和 replyTo(Messenger) 优质。
Messenger 的使用
- 服務(wù)端進程
- 創(chuàng)建一個 Service 來處理客戶端的連接請求
- 創(chuàng)建一個 Handler,并通過它來創(chuàng)建一個 Messenger 對象
- 在 Service 的 onBind 中返回 Messenger 對象底層的 IBinder
- 客戶端進程
- 綁定服務(wù)端的 Service,用服務(wù)端返回的 IBinder 對象創(chuàng)建一個 Messenger
- 用 Messenger 向服務(wù)端發(fā)送消息盆赤,消息的類型為 Message
通過以上操作贾富,就可以完成客戶端向服務(wù)端的單向通信了。如需支持服務(wù)端響應(yīng)客戶端:
- 客戶端進程
- 創(chuàng)建一個 Handler牺六,并通過它創(chuàng)建一個新的 Messenger 對象
- 將新創(chuàng)建的 Messenger 對象通過 Message 的 replyTo 參數(shù)傳遞給服務(wù)端進程
- 服務(wù)端進程
- 取出客戶端通過 replyTo 參數(shù)的傳遞過來的 Messenger 對象
- 使用 Messenger 對象回應(yīng)客戶端
4. AIDL
使用 AIDL 進行進程間通信的流程
- 服務(wù)端
- 創(chuàng)建一個 Service颤枪,用來監(jiān)聽客戶端的連接請求
- 創(chuàng)建一個 AIDL 文件,用來聲明暴露給客戶端的接口
- 在 Service 中實現(xiàn) AIDL 文件中聲明的接口
- 客戶端
- 綁定服務(wù)端的 Service
- 將服務(wù)端返回的 Binder 對象轉(zhuǎn)成 AIDL 接口所屬的類型
- 調(diào)用 AIDL 中的方法
AIDL 支持的數(shù)據(jù)類型
- 基本數(shù)據(jù)類型
- String 和 CharSequence
- ArrayList淑际,集合中的每個元素必須被 AIDL 支持
- HashMap畏纲,集合中的每個元素必須被 AIDL 支持,包括 key 和 value
- Parcelable:所有實現(xiàn)了 Parcelable 接口的類
- AIDL:所有的 AIDL 接口
5. ContentProvider
ContentProvider 是 Android 提供的不同應(yīng)用間數(shù)據(jù)共享的方式春缕,底層實現(xiàn)是 Binder盗胀。
Android 系統(tǒng)預(yù)置了許多 ContentProvider,比如通訊錄信息锄贼、日程表信息等票灰,要跨進程訪問這些信息,只需要通過 ContentResolver 的 query()宅荤、update()屑迂、insert() 和 delete() 方法即可。
ContentProvider 主要以表格的形式組織數(shù)據(jù)冯键,和數(shù)據(jù)庫相似惹盼。它還支持文件文件數(shù)據(jù),例如圖片惫确、視頻等手报。Android 提供的 MediaStore 就是文件類型的 ContentProvider。
雖然 ContentProvider 的底層數(shù)據(jù)看起來很像一個 SQLite 數(shù)據(jù)庫改化,但是它對數(shù)據(jù)的存儲方法并沒有任何要求掩蛤,我們既可以使用 SQLite 數(shù)據(jù)庫,也可以使用普通的文件陈肛,甚至可以采用內(nèi)存中的一個對象來進行數(shù)據(jù)的存儲揍鸟。
自定義 ContentProvider
- 繼承 ContentProvider 類,實現(xiàn) 6 個抽象方法:onCreate()燥爷、query()蜈亩、update()、insert()前翎、delete() 和 getType() 稚配。
- 建立數(shù)據(jù)存儲系統(tǒng),比較常用的使用 SQLite 數(shù)據(jù)庫港华。
- 注冊 ContentProvider道川,在 AndroidManifest 文件中聲明。
ContentProvider 的抽象方法
- onCreate() : ContentProvider 的初始化。
- getType() : 返回一個 Uri 請求所對應(yīng)的 MIME 類型冒萄。
- query()臊岸、update()、insert() 和 delete(): 數(shù)據(jù)的增刪改查尊流。
- 6 個方法均運行在 ContentProvider 的進程中帅戒,onCreate() 由系統(tǒng)回調(diào)并運行在主線程里,其他 5 個方法均由外界回調(diào)并運行在 Binder 線程池中崖技。
6. Socket
Socket逻住,套接字,是網(wǎng)絡(luò)通信中的概念迎献。分為流式套接字和用戶數(shù)據(jù)報套接字兩種瞎访,分別對應(yīng)網(wǎng)絡(luò)的傳輸控制層中的 TCP 和 UDP。
通過 Socket 不僅能實現(xiàn)進程間的通信吁恍,還可以實現(xiàn)設(shè)備間的通信扒秸,前提是通信的設(shè)備的 IP 地址互相可見。
IPC 方式比較
名稱 | 優(yōu)點 | 缺點 | 適用場景 |
---|---|---|---|
Bundle | 簡單易用 | 只能傳輸 Bundle 支持的數(shù)據(jù)類型 | 四大組件間的進程間通信 |
文件共享 | 簡單易用 | 不適合高并發(fā)場景冀瓦,不支持進程間的即時通信 | 無并發(fā)需求伴奥,交換簡單的數(shù)據(jù),對實時性要求不高 |
AIDL | 支持一對多并發(fā)通信咕幻,支持實時通信 | 使用比較復(fù)雜渔伯,需要處理好線程同步 | 一對多通信顶霞,有 RPC 需求 |
Messenger | 支持一對多串行通信肄程,支持實時通信 | 只能傳輸 Bundle 支持的數(shù)據(jù)類型,不能很好地處理高并發(fā)情形选浑,不支持 RPC | 低并發(fā)的一對多通信蓝厌,無 RPC 需求,或者有不需要返回結(jié)果的 RPC 需求 |
ContentProvider | 支持一對多并發(fā)數(shù)據(jù)共享古徒,可通過 Call 方法擴展其他操作 | 主要提供數(shù)據(jù)源的 CRUD 操作 | 一對多的進程間的數(shù)據(jù)共享 |
Socket | 支持一對多并發(fā)實時通信拓提,可以通過網(wǎng)絡(luò)傳輸字節(jié)流 | 使用比較復(fù)雜,不支持直接 RPC | 網(wǎng)絡(luò)數(shù)據(jù)交換 |
附
測試設(shè)備參數(shù)
- 型號:vivo Y66L
- 操作系統(tǒng):Funtouch OS 3.0(Android 6.0.1)
參考資料
任玉剛.Android 開發(fā)藝術(shù)探索[M].電子工業(yè)出版社:北京,2015:35-121.