一、進(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í)層次

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ù)端:
- 創(chuàng)建一個(gè)Handler對(duì)象,并實(shí)現(xiàn)handleMessage方法,用于接收和處理來自客戶端的消息。
- 創(chuàng)建一個(gè)Messenger作為送信人,封裝Handler。
- 用Messenger的getBinder()方法獲取一個(gè)IBinder對(duì)象,通過onBind返回給客戶端。
客戶端:
- 在Activity中綁定服務(wù)。
- 創(chuàng)建ServiceConnection并在其中使用 IBinder 將 Messenger實(shí)例化。
- 使用Messenger向服務(wù)端發(fā)送消息。
- 解綁服務(wù)。
- 服務(wù)端中在 handleMessage() 方法中接收每個(gè) Message。
以上實(shí)現(xiàn)的僅僅是單向通信,即客戶端給服務(wù)端發(fā)送消息,如果需要服務(wù)端給客戶端發(fā)送消息,需要接著上面的步驟繼續(xù):
- 在客戶端中創(chuàng)建一個(gè)Handler對(duì)象,用于處理服務(wù)端發(fā)過來的消息。
- 創(chuàng)建一個(gè)客戶端自己的Messenger對(duì)象,并封裝Handler。
- 將客戶端的Messenger對(duì)象賦給待發(fā)送的Message對(duì)象的replyTo字段。
- 在服務(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使用步驟
- 創(chuàng)建 .aidl 文件
此文件定義帶有方法簽名的編程接口。 - 實(shí)現(xiàn)接口
Android SDK 工具基于您的 .aidl 文件,使用 Java 編程語(yǔ)言生成一個(gè)接口。此接口具有一個(gè)名為 Stub 的內(nèi)部抽象類,用于擴(kuò)展 Binder 類并實(shí)現(xiàn) AIDL 接口中的方法。您必須擴(kuò)展 Stub 類并實(shí)現(xiàn)方法。 - 向客戶端公開該接口
實(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、readPermission、writePermission來設(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ì)比
