一益兄、進(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)程
沒有任何前臺組件冤荆,但仍能影響用戶在屏幕上看到東西朴则。
比如:
如果一個(gè)Activity在一個(gè)對話框運(yùn)行之后仍然是可視的;
輸入法彈出時(shí)钓简。
3 Service process 服務(wù)進(jìn)程
服務(wù)進(jìn)程不會(huì)直接為用戶所見乌妒。
比如:
在后臺播放mp3或者下載東西。
4 Background process 后臺進(jìn)程
比如:
Activity執(zhí)行了onStop外邓。
5 Empty process 空進(jìn)程
優(yōu)先級層次
RPC 和 IPC
RPC:Remote Procedure Call撤蚊,即遠(yuǎn)程過程調(diào)用,它是一種通過網(wǎng)絡(luò)從遠(yuǎn)程計(jì)算機(jī)程序上請求服務(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)可以識別的程度重虑,并將其從本地進(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)程間直接操作對方的數(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è)類的對象會(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)存間序列化和反序列化傳輸。
詳情請移步:
2 文件共享
對同一個(gè)文件先后寫讀芝加,從而實(shí)現(xiàn)傳輸硅卢,Linux機(jī)制下,可以對文件并發(fā)寫藏杖,所以要注意同步将塑。順便一提,Windows下不支持并發(fā)讀或?qū)憽?/p>
3 Messenger(基于Binder)
Messenger是基于AIDL實(shí)現(xiàn)的蝌麸,通過Message對象進(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ì)依次處理嘀略。
此外恤溶,還支持記錄客戶端對象的Messenger,然后可以實(shí)現(xiàn)一對多的通信帜羊;甚至作為一個(gè)轉(zhuǎn)接處咒程,任意兩個(gè)進(jìn)程都能通過服務(wù)端進(jìn)行通信。
與 AIDL 比較:
- 當(dāng)需要執(zhí)行 IPC 時(shí)讼育,為接口使用 Messenger 要比使用 AIDL 實(shí)現(xiàn)更加簡單帐姻,因?yàn)?Messenger 會(huì)將所有服務(wù)調(diào)用排入隊(duì)列,而純粹的 AIDL 接口會(huì)同時(shí)向服務(wù)發(fā)送多個(gè)請求奶段,服務(wù)隨后必須應(yīng)對多線程處理饥瓷。
- 對于大多數(shù)應(yīng)用,服務(wù)不需要執(zhí)行多線程處理痹籍,因此使用 Messenger 可讓服務(wù)一次處理一個(gè)調(diào)用呢铆。如果服務(wù)必須執(zhí)行多線程處理,則應(yīng)使用 AIDL 來定義接口蹲缠。
使用步驟
服務(wù)端:
- 創(chuàng)建一個(gè)Handler對象棺克,并實(shí)現(xiàn)handleMessage方法悠垛,用于接收和處理來自客戶端的消息。
- 創(chuàng)建一個(gè)Messenger作為送信人娜谊,封裝Handler确买。
- 用Messenger的getBinder()方法獲取一個(gè)IBinder對象,通過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對象钳踊,用于處理服務(wù)端發(fā)過來的消息衷敌。
- 創(chuàng)建一個(gè)客戶端自己的Messenger對象,并封裝Handler拓瞪。
- 將客戶端的Messenger對象賦給待發(fā)送的Message對象的replyTo字段缴罗。
- 在服務(wù)端的Handler處理Message時(shí)將客戶端的Messenger解析出來,并使用客戶端的Messenger對象給客戶端發(fā)送消息祭埂。
其實(shí)Messenger底層也是AIDL面氓。客戶端和服務(wù)端通訊蛆橡,就是普通的AIDL舌界,客戶端實(shí)例化Stub之后,通過Stub的send方法把消息發(fā)到服務(wù)端泰演。服務(wù)端和客戶端通訊:服務(wù)端通過解析Message的replyTo呻拌,獲得客戶端的Stub,然后通過send方法發(fā)送到客戶端睦焕。
注意:Service在聲明時(shí)必須對外開放藐握,即android:exported="true"
。
4 AIDL(基于Binder)
Google Doc:https://developer.android.google.cn/guide/components/aidl
AIDL:Android Interface Definition Language垃喊,即Android接口定義語言猾普。可以利用它定義客戶端與服務(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對象傳遞給客戶端窒悔,客戶端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 生成的接口或聲明的可打包類型屯耸。可選擇將 List/Map 用作“通用”類(例如蹭劈,List<String>疗绣、Map<String,Integer>)。
另一端實(shí)際接收的具體類始終是 ArrayList/HashMap铺韧,但生成的方法使用的是 List/Map 接口多矮。 - 實(shí)現(xiàn)了 Parcelable 接口的對象
- AIDL本身接口也可以在AIDL文件使用
AIDL使用步驟
- 創(chuàng)建 .aidl 文件
此文件定義帶有方法簽名的編程接口。 - 實(shí)現(xiàn)接口
Android SDK 工具基于您的 .aidl 文件,使用 Java 編程語言生成一個(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詳情請移步: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注冊時(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ù)庫管理類,但其實(shí)可以用文件充择、內(nèi)存數(shù)據(jù)等等一切來充當(dāng)數(shù)據(jù)源德玫,query返回的是一個(gè)Cursor,可以自定義繼承AbstractCursor的類來實(shí)現(xiàn)椎麦。
這里不再贅述宰僧,詳情可參考:https://blog.csdn.net/hzw2017/article/details/81123791