1. android中得IPC方式
- bundle
- 由于bundle實(shí)現(xiàn)了parcelable借口,且四大組件中得其中三個(gè)(activity,service,receive)都支持在intent中傳遞bundle數(shù)據(jù),比較方便實(shí)現(xiàn)不同的進(jìn)程間傳遞數(shù)據(jù)
- 使用文件共享
- 文件共享也是一種不錯(cuò)的進(jìn)程間通信方式,兩個(gè)進(jìn)程通過讀寫同一個(gè)文件來交換數(shù)據(jù),比如A進(jìn)程中把數(shù)據(jù)寫入文件,B進(jìn)程通過讀取這個(gè)文件來獲取數(shù)據(jù)。但是這種方式也是又一定局限性的,比如并發(fā)讀寫的問題會(huì)導(dǎo)致我們讀出的數(shù)據(jù)不是最新的,因此要避免并發(fā)讀寫的發(fā)生或者考慮使用線程同步來限制多個(gè)線程的讀寫操作。基于這樣的問題,文件共享方式適合對(duì)數(shù)據(jù)同步要求不高的進(jìn)程之間進(jìn)行通信。
- 使用Messenger
- Messenger是一種輕量級(jí)的IPC方案,它的底層實(shí)現(xiàn)是AIDL,通過Messenger可以在不同進(jìn)程中傳遞Message對(duì)象,在Message中放入我們需要傳遞的數(shù)據(jù)就可以輕松實(shí)現(xiàn)數(shù)據(jù)在進(jìn)程間傳遞了。
- 使用AIDL
- Messenger是以串行的方式處理客戶端的請(qǐng)求,如果有大量的請(qǐng)求同時(shí)發(fā)送到服務(wù)端,服務(wù)端仍然只能一個(gè)一個(gè)處理,此時(shí)Messenger就不大合適了,同時(shí)Messenger的作用是為了傳遞消息,且只能傳遞Bundle支持的數(shù)據(jù)類型,很多時(shí)候需要跨進(jìn)程調(diào)用服務(wù)端的方法,這時(shí)候可以實(shí)用AIDL來實(shí)現(xiàn)跨進(jìn)程的方法調(diào)用。AIDL也是Messenger的底層實(shí)現(xiàn),因此Messenger本質(zhì)上也是AIDL,只不過系統(tǒng)作了封裝。
2. 原理
- 在app層:binder是客戶端和服務(wù)端通信的媒介,當(dāng)bindservice的時(shí)候,服務(wù)端會(huì)返回一個(gè)包含了服務(wù)端業(yè)務(wù)調(diào)用的binder對(duì)象,通過這個(gè)binder對(duì)象,客戶端就可以獲取到服務(wù)端提供的服務(wù)或者數(shù)據(jù),這里面的服務(wù)包含了普通服務(wù)和基于AIDL的服務(wù);
- 在framework層,binder是各種Manger(ActivityManger,windowManger等)和響應(yīng)xxxMangerService的橋梁;
- 在native層.binder是創(chuàng)建了ServiceManger以及BpBinder/BBinder模型,搭建binder的橋梁;
3. 具體使用
1. 客戶端
- 在main文件夾下建aidl文件,這個(gè)需要特別注意在客戶端也要建立相同包名,文件名的aidl文件;
- 在aidl中定義在服務(wù)端要實(shí)現(xiàn)的方法,此時(shí)注意aidl語法接受的參數(shù)類型;
- 新建完成之后點(diǎn)擊構(gòu)建,在build->generated->source->aidl->debug->包名->就會(huì)生成一個(gè)與剛剛新建的同名的接口文件;
- 以上部分與服務(wù)端同樣,做相同的工作,-------------
- 客戶端實(shí)現(xiàn)具體的邏輯,連接服務(wù),實(shí)現(xiàn)通訊
2. 服務(wù)端
- 前三部是與客戶端相同,
- 實(shí)現(xiàn)stub操作,獲取到一個(gè)Ibinder對(duì)象,實(shí)現(xiàn)aidl文件中定義的方法;
3. 解析生成的aidl.java文件
-
簡單的分類對(duì)于生成的aidl文件
IRemoteAidl Stub abstract extend IBinder implements IRemoteAidl poxy implements IRemoteAidl poxy() asBinder() getInterfaceDescriptor() add() Stub() IBinder asInterface() IRemoteAidl asBinder() IBinder onTransact() add() 對(duì)于客戶端只需要獲取到IRemoteAidl對(duì)象來調(diào)用add
對(duì)于服務(wù)端需要獲取到Ibinder對(duì)象來做返回;
可能大家也注意點(diǎn) Proxy 這里是private權(quán)限的,外部是無法訪問的,但這里是 Android 有意為之,拋出了 asInterface 方法,這樣避免了對(duì) Proxy可能的修改。
Proxy 是寫入?yún)?shù),讀取值;Stub 是讀取參數(shù),寫入值,剛好也就是從客戶端到服務(wù)端的步驟,poxy,寫入?yún)?shù),stub獲取到參數(shù)經(jīng)過處理然后寫入,poxy就可以讀取到值了;
4. 常見的問題
- 只有一個(gè)service,不能安裝應(yīng)用的情況Error running app: Default ActivityNot Found。;
- 默認(rèn)情況下安裝默認(rèn)設(shè)置Lunche工程時(shí)是需要Activity的
- Run configurations ->general->lunch:nothing
- 客戶端和服務(wù)端必須擁有相同的aidl文件的問題(包括包名,文件名都要相同),包括方法的定義順序等都必須要相同,不然會(huì)出現(xiàn)Java.lang.SecurityException: Binder invocation to an incorrect interface 這個(gè)錯(cuò)誤。
- service 的注冊(cè)配置的問題;service要和client運(yùn)行在不同的進(jìn)程中,所以一定要記得去配置procress屬性;
- service的啟動(dòng)問題;
- 使用bindService的方式去啟動(dòng)
-
這個(gè)地方涉及到安卓中開啟多進(jìn)程的方式:如果你想在一個(gè)應(yīng)用中使用多個(gè)進(jìn)程,通過清單文件給四大組件添加android:process屬性,就可以很方便的開啟多進(jìn)程.
AndroidManifest.png- 如圖開啟了三個(gè)進(jìn)程:默認(rèn)進(jìn)程是MainActivity
- $ adb shell ps | grep com.szysky 你可以直接使用adb shell ps這會(huì)把系統(tǒng)所有進(jìn)程展示出來,
- 你可能已經(jīng)發(fā)現(xiàn)在創(chuàng)建新進(jìn)程的時(shí)候使用兩種不同的方式
- 當(dāng)以:開頭的進(jìn)程,屬于當(dāng)前應(yīng)用的私有進(jìn)程,其他應(yīng)用的組件不可以和它跑在同一個(gè)進(jìn)程
- 當(dāng)不以:開頭,那么進(jìn)程屬于全局進(jìn)程,其他應(yīng)用通過ShareUID方法可以和它跑在同一個(gè)進(jìn)程
- Android系統(tǒng)會(huì)為每一個(gè)應(yīng)用分配唯一的UID. 相同UID的應(yīng)用才能共享數(shù)據(jù). 但是兩個(gè)應(yīng)用通過ShareUID跑在同一個(gè)進(jìn)程是有要求的. 除了具有相同的ShareUID并且還要簽名相同才可以. 這時(shí)如果不在同一進(jìn)程他們之間可以共享data目錄,組件信息等. 如果還在同一進(jìn)程, 那么他們還能共享內(nèi)存數(shù)據(jù).
