1、IPC基礎及概念html
1.多進程模式java
a.進程&線程linux
二者關係: 一個進程可包含多個線程,即一個應用程序上能夠同時執行多個任務。android
- 主線程(UI線程):UI操做
- 有限個子線程:耗時操做
注意:不可在主線程作大量耗時操做,會致使ANR(應用無響應)。git
b.開啓多進程模式的方式:shell
android:process
,進程名的命名規則:
android:process=":remote"
,表示進程名爲com.example.myapplication:remote
。android:process="com.example.myapplication.remote"
。UID&ShareUID:數據庫
- Android系統爲每一個應用分配一個惟一的UID,具備相同UID的應用才能共享數據。
- 兩個應用經過ShareUID跑在同一進程的條件:ShareUID相同且簽名也相同。
- 知足上述條件的兩個應用,不管是否跑在同一進程,它們可共享data目錄,組件信息。
- 若跑在同一進程,它們除了可共享data目錄、組件信息,還可共享內存數據。它們就像是一個應用的兩個部分。
c.查看進程信息的方法:緩存
adb shell ps|grep 包名
。d.須要進程間通訊的必要性:全部運行在不一樣進程的四大組件,只要它們之間須要經過內存在共享數據,都會共享失敗。安全
緣由:因爲Android爲每一個應用分配了獨立的虛擬機,不一樣的虛擬機在內存分配上有不一樣的地址空間,這會致使在不一樣的虛擬機中訪問同一個類的對象會產生多份副本。bash
e.多進程形成的影響,總結爲如下四方面:
①靜態變量和單例模式失效。
②線程同步機制失效。
③SharedPreference的不可靠降低。
④Application屢次建立。
推薦閱讀:關於Android多進程
2.序列化
a.序列化的介紹
- 含義:序列化表示將一個對象轉換成可存儲或可傳輸的狀態。序列化後的對象能夠在網絡上進行傳輸,也能夠存儲到本地。
- 場景:須要經過Intent和Binder等傳輸類對象就必須完成對象的序列化過程。
- 兩種方式:實現Serializable/Parcelable接口。
b.Serializable接口和Parcelable接口的比較:
c.serialVersionUID
注意:兩種變量不會參與序列化過程:
- 靜態成員變量屬於類,不屬於對象。
- 用transient關鍵字標記的成員變量。
推薦閱讀:序列化Serializable和Parcelable的理解和區別
3.IPC簡介
a.IPC(Inter-Process Communication,跨進程通訊):指兩個進程之間進行數據交換的過程。
b.任何一個操做系統都有對應的IPC機制。
c.IPC的使用場景:
d.Android的進程架構:每個Android進程都是獨立的,且都由兩部分組成,一部分是用戶空間,另外一部分是內核空間,以下圖:
如此設計的優勢:
4.Binder機制
a.概念:
b.Android是基於Linux內核基礎上設計的,卻沒有把管道/消息隊列/共享內存/信號量/Socket等一些IPC通訊手段做爲Android的主要IPC方式,而是新增了Binder機制,其優勢有:
方式 | 拷貝次數 | 操做難度 |
---|---|---|
Binder | 1 | 簡易 |
消息隊列 | 2 | 簡易 |
Socket | 2 | 簡易 |
管道 | 2 | 簡易 |
共享內存 | 0 | 複雜 |
從Android進程架構角度分析:對於消息隊列、Socket和管道來講,數據先從發送方的緩存區拷貝到內核開闢的緩存區中,再從內核緩存區拷貝到接收方的緩存區,一共兩次拷貝,如圖:
而對於Binder來講,數據從發送方的緩存區拷貝到內核的緩存區,而接收方的緩存區與內核的緩存區是映射到同一塊物理地址的,節省了一次數據拷貝的過程,如圖:
因爲共享內存操做複雜,綜合來看,Binder的傳輸效率是最好的。
實現C/S架構方便:Linux的衆IPC方式除了Socket之外都不是基於C/S架構,而Socket主要用於網絡間的通訊且傳輸效率較低。Binder基於C/S 架構 ,Server端與Client端相對獨立,穩定性較好。
安全性高:傳統Linux IPC的接收方沒法得到對方進程可靠的UID/PID,從而沒法鑑別對方身份;而Binder機制爲每一個進程分配了UID/PID且在Binder通訊時會根據UID/PID進行有效性檢測。
c.Binder框架定義了四個角色:Server,Client,ServiceManager和Binder驅動。
其中Server、Client、ServiceManager運行於用戶空間,Binder驅動運行於內核空間。關係如圖:
下面簡單介紹這四個角色:
d.代理模式Proxy:給某個對象提供一個代理對象,並由代理對象控制對原對象的訪問。如圖:
代理模式的組成:
推薦閱讀:代理模式
e.Binder 工做原理:
後面會經過AIDL和Messager更深入地體會這一工做原理。
推薦閱讀:Android - Binder驅動、Binder設計與實現、Binder系列、
3、IPC方式
由上圖能夠看到,其餘一些IPC方式實際都是經過Binder來實現,只不過封裝方式不一樣。接下來分別總結其餘六種IPC方式:
1.使用Bundle
a.Bundle:支持在Activity、Service和Receiver之間經過**Intent.putExtra()**傳遞Bundle數據。
Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putString("xxx","xxx");
intent.putExtra("data", bundle);
複製代碼
b.原理:Bundle實現Parcelable接口,它可方便的在不一樣的進程中傳輸。
c.注意:Bundle不支持的數據類型沒法在進程中被傳遞。
思考下面這種狀況: Q:在A進程進行計算後的結果不是Bundle所支持的數據類型,該如何傳給B進程? A:將在A進程進行的計算過程轉移到B進程中的一個Service裏去作,這樣可成功避免進程間的通訊問題。
推薦閱讀:經過Bundle在Android Activity間傳遞數據
2.使用文件共享
a.文件共享:兩個進程經過讀/寫同一個文件來交換數據。好比A進程把數據寫入文件,B進程經過讀取這個文件來獲取數據。
b.適用狀況:對數據同步要求不高的進程之間進行通訊,而且要妥善處理併發讀/寫的問題。
c.雖然SharedPreferences也是文件存儲的一種,但不建議採用。
3.使用AIDL
a.AIDL(Android Interface Definition Language,Android接口定義語言):若是在一個進程中要調用另外一個進程中對象的方法,可以使用AIDL生成可序列化的參數,AIDL會生成一個服務端對象的代理類,經過它客戶端實現間接調用服務端對象的方法。
b.可支持的數據類型:
注意:除了基本數據類型,其它類型的參數必須標上方向:in、out或inout,用於表示在跨進程通訊中數據的流向。
- in
- 表示數據只能由客戶端流向服務端。
- 服務端將會接收到這個對象的完整數據,但在服務端修改它不會對客戶端輸入的對象產生影響。
- out
- 表示數據只能由服務端流向客戶端。
- 服務端將會接收到這個對象的的空對象,但在服務端對接收到的空對象有任何修改以後客戶端將會同步變更。
- inout
- 表示數據可在服務端與客戶端之間雙向流通。
- 服務端將會接收到客戶端傳來對象的完整信息,且客戶端將會同步服務端對該對象的任何變更。
c.兩種AIDL文件:
注意:
- 自定義的Parcelable對象必須把java文件和自定義的AIDL文件顯式的import進來,不管是否在同一包內。
- AIDL文件用到自定義Parcelable的對象,必須新建一個和它同名的AIDL文件,並在其中聲明它爲Parcelable類型。
d.AIDL的本質是系統提供了一套可快速實現Binder的工具。關鍵類和方法:
經過此處實例具體瞭解AIDL實現IPC的流程:
推薦閱讀:Android中AIDL的工做原理
e.實現方法:
總結:服務端裏的某個Service給和它綁定的特定客戶端進程提供Binder對象,客戶端經過AIDL接口的靜態方法asInterface() 將Binder對象轉化成AIDL接口的代理對象,經過這個代理對象就能夠發起遠程調用請求。
f.可能產生ANR的情形:
g.解決客戶端頻繁調用服務器方法致使性能極大損耗的辦法:實現觀察者模式。即當客戶端關注的數據發生變化時,再讓服務端通知客戶端去作相應的業務處理。
好比:每一個客戶端的請求Listener傳遞給服務端,服務端用一個list保存,當數據變化時服務器再依次通知,此時客戶端就用Listener進行回調處理。注意要用Handler切換到主線程。
h.AIDL 解註冊失敗
須要用到RemoteCallBackList:Android系統專門提供的用於刪除跨進程listener的接口。其內部自動實現了線程同步的功能。
4.使用Messager
a.Messenger:輕量級的IPC方案,經過它可在不一樣進程中傳遞Message對象。
Messenger.send(Message);
複製代碼
相關記憶:
- Handler:主要進行線程間的數據通訊。
- Messenger:進程間的數據通訊。
b.特色:
c.實現方法:
d.Message的缺點:
解決辦法:考慮使用AIDL實現IPC。
推薦閱讀:超簡單的Binder,AIDL和Messenger的原理及使用流程
5.使用ContentProvider
a.ContentProvider:是Android提供的專門用來進行不一樣應用間數據共享的方式。
底層一樣是經過Binder實現的。
b.注意:
基礎篇: 組件篇之ContentProvider
6.使用Socket
a.Socket(套接字):不只可跨進程,還能夠跨設備通訊。
b.使用類型
c.實現方法:TCP/UDP
d.注意:使用Socket進行通訊
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
複製代碼
推薦閱讀:這是一份很詳細的Socket使用攻略
綜上,以上六種IPC方式的優缺點和使用場景見下圖:
四.Binder鏈接池
a.背景:有多個業務模塊都須要AIDL來進行IPC,此時須要爲每一個模塊建立特定的aidl文件,那麼相應的Service就會不少。必然會出現系統資源耗費嚴重、應用過分重量級的問題。
b.做用:將每一個業務模塊的Binder請求統一轉發到一個遠程Service中去執行,從而避免重複建立Service。
c.工做原理:每一個業務模塊建立本身的AIDL接口並實現此接口,而後向服務端提供本身的惟一標識和其對應的Binder對象。服務端只須要一個Service,服務器提供一個queryBinder接口,它會根據業務模塊的特徵來返回相應的Binder對像,不一樣的業務模塊拿到所需的Binder對象後就可進行遠程方法的調用了。流程如圖:
d.實現方式:
實例:細說Binder鏈接池
如今能夠回答如下問題:
Q:在Android開發中提升開發效率的方法?
A:使用Binder鏈接池,避免反覆建立Service,統一管理和維護AIDL。
推薦閱讀:Android的IPC機制、Android跨進程通訊IPC
但願這篇文章對你有幫助~