Android進(jìn)程通信

參考:https://blog.csdn.net/hzw2017/article/details/81275438

一、進(jìn)程

Android中進(jìn)程分為5種:

1 Foreground process 前端進(jìn)程

目前顯示在屏幕上和用戶交互的進(jìn)程。
比如:
頂層可交互的Activity(已執(zhí)行onResume);
有個(gè)Service,并綁定到跟用戶正在交互的Activity;
在Service里調(diào)用了startForeground函數(shù);
正在執(zhí)行onReceive的BroadcastReceiver。

2 Visible process 可見進(jìn)程

沒有任何前臺(tái)組件,但仍能影響用戶在屏幕上看到東西。
比如:
如果一個(gè)Activity在一個(gè)對(duì)話框運(yùn)行之后仍然是可視的;
輸入法彈出時(shí)。

3 Service process 服務(wù)進(jìn)程

服務(wù)進(jìn)程不會(huì)直接為用戶所見。
比如:
在后臺(tái)播放mp3或者下載東西。

4 Background process 后臺(tái)進(jìn)程

比如:
Activity執(zhí)行了onStop。

5 Empty process 空進(jìn)程
優(yōu)先級(jí)層次
Android進(jìn)程層次.png

RPC 和 IPC

RPC:Remote Procedure Call,即遠(yuǎn)程過程調(diào)用,它是一種通過網(wǎng)絡(luò)從遠(yuǎn)程計(jì)算機(jī)程序上請(qǐng)求服務(wù),在不需要了解底層網(wǎng)絡(luò)技術(shù)的協(xié)議下,即可獲取計(jì)算機(jī)進(jìn)程中的數(shù)據(jù)。RPC使得開發(fā)包括網(wǎng)絡(luò)分布式多程序在內(nèi)的應(yīng)用程序更加容易。
RPC在OSI網(wǎng)絡(luò)通信7層模型中,位于傳輸層與應(yīng)用層之間,即位于會(huì)話層。

RPC可以說客戶端調(diào)用服務(wù)端的接口的過程,是面向接口的編程。

RPC與IPC的關(guān)系:
Android 利用遠(yuǎn)程過程調(diào)用 (RPC) 提供了一種進(jìn)程間通信 (IPC) 機(jī)制,通過這種機(jī)制,由 Activity 或其他應(yīng)用組件調(diào)用的方法將(在其他進(jìn)程中)遠(yuǎn)程執(zhí)行,而所有結(jié)果將返回給調(diào)用方。
這就要求把方法調(diào)用及其數(shù)據(jù)分解至操作系統(tǒng)可以識(shí)別的程度,并將其從本地進(jìn)程和地址空間傳輸至遠(yuǎn)程進(jìn)程和地址空間,然后在遠(yuǎn)程進(jìn)程中重新組裝并執(zhí)行該調(diào)用。然后,返回值將沿相反方向傳輸回來。Android 提供了執(zhí)行這些 IPC 事務(wù)所需的全部代碼,因此您只需集中精力定義和實(shí)現(xiàn) RPC 編程接口即可。
要執(zhí)行 IPC,必須使用 bindService() 將應(yīng)用綁定到服務(wù)上。

也就是說,RPC在的Android具體體現(xiàn),是依賴 bindService()的方式,在onBind方法將服務(wù)端的計(jì)算結(jié)果返回給客戶端(Activity等組件)的過程。

IPC:Inter-Process Communication,即進(jìn)程間通信,是指進(jìn)程間數(shù)據(jù)交互的過程。

Android底層是基于Linux,而Linux基于安全考慮,是不允許兩個(gè)進(jìn)程間直接操作對(duì)方的數(shù)據(jù),這就是進(jìn)程隔離。

在Linux系統(tǒng)中,虛擬內(nèi)存機(jī)制為每個(gè)進(jìn)程分配了線性連續(xù)的內(nèi)存空間,操作系統(tǒng)將這種虛擬內(nèi)存空間映射到物理內(nèi)存空間,每個(gè)進(jìn)程有自己的虛擬內(nèi)存空間,進(jìn)而不能操作其他進(jìn)程的內(nèi)存空間,每個(gè)進(jìn)程只能操作自己的虛擬內(nèi)存空間,只有操作系統(tǒng)才有權(quán)限操作物理內(nèi)存空間。進(jìn)程隔離保證了每個(gè)進(jìn)程的內(nèi)存安全,但是在大多數(shù)情形下,不同進(jìn)程間的數(shù)據(jù)通訊是不可避免的,因此操作系統(tǒng)必須提供跨進(jìn)程通信機(jī)制。

Android應(yīng)用中使用多進(jìn)程:

  • 在AndroidManifest.xml中聲明組件時(shí),用android:process屬性來指定進(jìn)程。

  • 不指定process屬性,則默認(rèn)運(yùn)行在主進(jìn)程中,主進(jìn)程名字為包名。

  • android:process = package:remote,將運(yùn)行在package:remote進(jìn)程中,屬于全局進(jìn)程,其他具有相同shareUID與簽名的APP可以跑在這個(gè)進(jìn)程中。

  • android:process = :remote ,將運(yùn)行在默認(rèn)包名:remote進(jìn)程中,而且是APP的私有進(jìn)程,不允許其他APP的組件來訪問。

多進(jìn)程引發(fā)的問題

  • 靜態(tài)成員和單例失效:每個(gè)進(jìn)程保持各自的靜態(tài)成員和單例,相互獨(dú)立。

  • 線程同步機(jī)制失效:每個(gè)進(jìn)程有自己的線程鎖。

  • SharedPreferences可靠性下降:不支持并發(fā)寫,會(huì)出現(xiàn)臟數(shù)據(jù)。

  • Application多次創(chuàng)建:不同進(jìn)程跑在不同虛擬機(jī),每個(gè)虛擬機(jī)啟動(dòng)會(huì)創(chuàng)建自己的Application,自定義Application時(shí)生命周期會(huì)混亂。

綜上,不同進(jìn)程擁有各自獨(dú)立的虛擬機(jī)、Application、內(nèi)存空間,不同進(jìn)程訪問同一個(gè)類的對(duì)象會(huì)有不同的副本,由此引發(fā)一系列問題。


二、進(jìn)程間通信

雖然Android是基于Linux,但并不能繼承Linux中的進(jìn)程通信的方式,Android有著自己進(jìn)程間通信方式。

1 Bundle (四大組件間)

可傳遞基本類型、String、實(shí)現(xiàn)了Serializable或Parcelable接口的數(shù)據(jù)結(jié)構(gòu)。

Serializable是Java的序列化方法,Parcelable是Android的序列化方法。前者代碼量少(僅一句),但I(xiàn)/O開銷較大,一般用于輸出到磁盤或網(wǎng)卡;后者實(shí)現(xiàn)代碼多,效率高,一般用戶內(nèi)存間序列化和反序列化傳輸。

詳情請(qǐng)移步:

2 文件共享

對(duì)同一個(gè)文件先后寫讀,從而實(shí)現(xiàn)傳輸,Linux機(jī)制下,可以對(duì)文件并發(fā)寫,所以要注意同步。順便一提,Windows下不支持并發(fā)讀或?qū)憽?/p>

3 Messenger(基于Binder)

Messenger是基于AIDL實(shí)現(xiàn)的,通過Message對(duì)象進(jìn)行跨進(jìn)程通信,類似于Handler發(fā)送消息實(shí)現(xiàn)線程間通信。服務(wù)端(被動(dòng)方)提供一個(gè)Service來處理客戶端(主動(dòng)方)連接,維護(hù)一個(gè)Handler來創(chuàng)建Messenger,在onBind時(shí)返回Messenger的binder。

雙方用Messenger來發(fā)送數(shù)據(jù),用Handler來處理數(shù)據(jù)。Messenger處理數(shù)據(jù)依靠Handler,所以是串行的,也就是說,Handler接到多個(gè)message時(shí),就要排隊(duì)依次處理。

此外,還支持記錄客戶端對(duì)象的Messenger,然后可以實(shí)現(xiàn)一對(duì)多的通信;甚至作為一個(gè)轉(zhuǎn)接處,任意兩個(gè)進(jìn)程都能通過服務(wù)端進(jìn)行通信。

與 AIDL 比較:
  • 當(dāng)需要執(zhí)行 IPC 時(shí),為接口使用 Messenger 要比使用 AIDL 實(shí)現(xiàn)更加簡(jiǎn)單,因?yàn)?Messenger 會(huì)將所有服務(wù)調(diào)用排入隊(duì)列,而純粹的 AIDL 接口會(huì)同時(shí)向服務(wù)發(fā)送多個(gè)請(qǐng)求,服務(wù)隨后必須應(yīng)對(duì)多線程處理。
  • 對(duì)于大多數(shù)應(yīng)用,服務(wù)不需要執(zhí)行多線程處理,因此使用 Messenger 可讓服務(wù)一次處理一個(gè)調(diào)用。如果服務(wù)必須執(zhí)行多線程處理,則應(yīng)使用 AIDL 來定義接口。
使用步驟
服務(wù)端:
  1. 創(chuàng)建一個(gè)Handler對(duì)象,并實(shí)現(xiàn)handleMessage方法,用于接收和處理來自客戶端的消息。
  2. 創(chuàng)建一個(gè)Messenger作為送信人,封裝Handler。
  3. 用Messenger的getBinder()方法獲取一個(gè)IBinder對(duì)象,通過onBind返回給客戶端。
客戶端:
  1. 在Activity中綁定服務(wù)。
  2. 創(chuàng)建ServiceConnection并在其中使用 IBinder 將 Messenger實(shí)例化。
  3. 使用Messenger向服務(wù)端發(fā)送消息。
  4. 解綁服務(wù)。
  5. 服務(wù)端中在 handleMessage() 方法中接收每個(gè) Message。

以上實(shí)現(xiàn)的僅僅是單向通信,即客戶端給服務(wù)端發(fā)送消息,如果需要服務(wù)端給客戶端發(fā)送消息,需要接著上面的步驟繼續(xù):

  1. 在客戶端中創(chuàng)建一個(gè)Handler對(duì)象,用于處理服務(wù)端發(fā)過來的消息。
  2. 創(chuàng)建一個(gè)客戶端自己的Messenger對(duì)象,并封裝Handler。
  3. 將客戶端的Messenger對(duì)象賦給待發(fā)送的Message對(duì)象的replyTo字段。
  4. 在服務(wù)端的Handler處理Message時(shí)將客戶端的Messenger解析出來,并使用客戶端的Messenger對(duì)象給客戶端發(fā)送消息。

其實(shí)Messenger底層也是AIDL??蛻舳撕头?wù)端通訊,就是普通的AIDL,客戶端實(shí)例化Stub之后,通過Stub的send方法把消息發(fā)到服務(wù)端。服務(wù)端和客戶端通訊:服務(wù)端通過解析Message的replyTo,獲得客戶端的Stub,然后通過send方法發(fā)送到客戶端。

注意:Service在聲明時(shí)必須對(duì)外開放,即android:exported="true"。

4 AIDL(基于Binder)

Google Doc:https://developer.android.google.cn/guide/components/aidl

AIDL:Android Interface Definition Language,即Android接口定義語(yǔ)言??梢岳盟x客戶端與服務(wù)使用進(jìn)程間通信 (IPC) 進(jìn)行相互通信時(shí)都認(rèn)可的編程接口。

:只有允許不同應(yīng)用的客戶端用 IPC 方式訪問服務(wù),并且想要在服務(wù)中處理多線程時(shí),才有必要使用 AIDL。 如果不需要執(zhí)行跨越不同應(yīng)用的并發(fā) IPC,就應(yīng)該通過實(shí)現(xiàn)一個(gè) Binder創(chuàng)建接口;或者,如果想執(zhí)行 IPC,但根本不需要處理多線程,則使用 Messenger 類來實(shí)現(xiàn)接口。無論如何,在實(shí)現(xiàn) AIDL 之前,需要理解綁定服務(wù)。

從某種意義上說AIDL其實(shí)是一個(gè)模板,因?yàn)樵谑褂眠^程中,實(shí)際起作用的并不是AIDL文件,而是據(jù)此而生成的一個(gè)IInterface的實(shí)例代碼,AIDL其實(shí)是為了避免我們重復(fù)編寫代碼而出現(xiàn)的一個(gè)模板。

通過編寫aidl文件來設(shè)計(jì)想要暴露的接口,編譯后會(huì)自動(dòng)生成相應(yīng)的java文件,服務(wù)器將接口的具體實(shí)現(xiàn)寫在Stub中,用IBinder對(duì)象傳遞給客戶端,客戶端bindService的時(shí)候,用asInterface的形式將IBinder還原成接口,再調(diào)用其中的方法。

AIDL支持的數(shù)據(jù)類型
  • 基本數(shù)據(jù)類型(int、long、char、boolean、double、byte、short、float)
  • String 和 CharSequence
  • List、Map集合:
    List/Map中的所有元素都必須是以上列表中支持的數(shù)據(jù)類型、其他 AIDL 生成的接口或聲明的可打包類型??蛇x擇將 List/Map 用作“通用”類(例如,List<String>、Map<String,Integer>)。
    另一端實(shí)際接收的具體類始終是 ArrayList/HashMap,但生成的方法使用的是 List/Map 接口。
  • 實(shí)現(xiàn)了 Parcelable 接口的對(duì)象
  • AIDL本身接口也可以在AIDL文件使用

AIDL使用步驟

  1. 創(chuàng)建 .aidl 文件
    此文件定義帶有方法簽名的編程接口。
  2. 實(shí)現(xiàn)接口
    Android SDK 工具基于您的 .aidl 文件,使用 Java 編程語(yǔ)言生成一個(gè)接口。此接口具有一個(gè)名為 Stub 的內(nèi)部抽象類,用于擴(kuò)展 Binder 類并實(shí)現(xiàn) AIDL 接口中的方法。您必須擴(kuò)展 Stub 類并實(shí)現(xiàn)方法。
  3. 向客戶端公開該接口
    實(shí)現(xiàn) Service 并重寫 onBind() 以返回 Stub 類的實(shí)現(xiàn)。

AIDL詳情請(qǐng)移步:Android進(jìn)程通信-AIDL

5 ContentProvider(基于Binder)

Google Doc: https://developer.android.google.cn/guide/topics/providers/content-providers

系統(tǒng)四大組件之一,底層也是基于Binder實(shí)現(xiàn)的,是Android跨進(jìn)程實(shí)現(xiàn)數(shù)據(jù)共享的標(biāo)準(zhǔn)方式。
ContentProvider主要用于在不同的應(yīng)用程序間實(shí)現(xiàn)數(shù)據(jù)共享,允許一個(gè)程序訪問另外一個(gè)程序中的數(shù)據(jù),還能保證數(shù)據(jù)訪問的安全性,可以說天生就是為進(jìn)程通信而生的。

  • 自己實(shí)現(xiàn)一個(gè)ContentProvider需要實(shí)現(xiàn)6個(gè)方法,其中onCreate是主線程中回調(diào)的,其他方法是運(yùn)行在Binder之中的。
  • 自定義的ContentProvider注冊(cè)時(shí)要提供authorities屬性,應(yīng)用需要訪問的時(shí)候?qū)傩园b成Uri.parse("content://authorities")。
  • 還可以設(shè)置permission、readPermissionwritePermission來設(shè)置權(quán)限。
  • ContentProvider有query,delete,insert等方法,看起來貌似是一個(gè)數(shù)據(jù)庫(kù)管理類,但其實(shí)可以用文件、內(nèi)存數(shù)據(jù)等等一切來充當(dāng)數(shù)據(jù)源,query返回的是一個(gè)Cursor,可以自定義繼承AbstractCursor的類來實(shí)現(xiàn)。

這里不再贅述,詳情可參考:https://blog.csdn.net/hzw2017/article/details/81123791

6 Socket(網(wǎng)絡(luò))

請(qǐng)移步:網(wǎng)絡(luò)通信-Socket

6種IPC方式對(duì)比

IPC方式對(duì)比.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容