Android IPC機制

IPC(進程間通信或者跨進程通信):指兩個進程間交換數(shù)據(jù)的過程棠耕。

線程:線程是CPU調(diào)度的最小單位吹零,是一種有限的系統(tǒng)資源漫雕。
進程:進程一般指一個執(zhí)行單元滨嘱,在PC或者移動設備上指一個程序或者應用。
一個進程可以包含多個線程浸间,最簡單情況下太雨,一個進程只包含一個線程(即主線程)。Android中主線程也叫作UI線程魁蒜。

Android中的多進程模式

Android中只能通過給四大組件指定 android:process 屬性囊扳,來可以開啟多進程模式
特殊情況,還有一種非常規(guī)的多進程方法:通過JNI在native層去fork一個新進程

開啟多進程模式

正常情況下兜看,在Android中多進程是指一個應用中存在多個進程的情況锥咸。
在指定android:process屬性值里面指定當前組件運行在那個進程,指定的時候其中的“ : ”表示在當前進程前附加當前包名细移,另一種就是完整的聲明方式搏予,直接直接定具體進行名

多進程模式的運行機制

所有運行在不同進程中的四大組件,只要他們之間需要通過內(nèi)存來共享數(shù)據(jù)弧轧,都會共享失敗雪侥,這也是多進程帶來的主要影響。
一般來說精绎,使用多進程會造成如下幾方面問題:

  • (1)靜態(tài)成員和單例模式完全失效
  • (2)線程同步機制完全失效校镐,不同進程針對的是不同對象
  • (3)SharedPreference可靠性下降,不支持兩個進程同時執(zhí)行寫操作捺典,否則會造成一定幾率的數(shù)據(jù)丟失
  • (4)Application會多次創(chuàng)建

IPC基礎概念

主要包含三個方面內(nèi)容:serializable接口鸟廓、Parcelable接口、Binder
serializable和Parcelable接口襟己,可以完成對象的序列化過程引谜,當我么你需要通過Intent和Binder傳輸數(shù)據(jù)時就需要用到

Serializable接口

Serializable接口是Java所提供的一個序列化接口,它是一個空接口擎浴,為對象提供標準的序列化和反序列化操作员咽。使用的時候在類的聲明中實現(xiàn)Serializable接口即可,或者再聲明一個私有靜態(tài)常量serialVersionUID贮预,系統(tǒng)會自動實現(xiàn)默認序列化贝室。
serialVersionUID作用:序列化的時候?qū)懭胛募敺葱蛄谢臅r候系統(tǒng)會去檢測文件中的serialVersionUID是否一致滑频,如果一致就說明序列化的類版本和當前類的版本相同,這時候可成功反序列化银伟;否則就說明發(fā)生了一些改變,就無法反序列化。
如何進行對象的序列化和反序列化圆米,只需要采用ObjectOutPutStream和ObjectInputStream即可


序列化和反序列化示例

需要注意的是:靜態(tài)成員變量屬于類,不屬于對象桂肌,所以不會參與序列化過程;其次還可以使用transient關鍵字標記成員變量不參與序列化過程。
另外螃宙,序列化和反序列化的實現(xiàn)過程也是可以改變的芹助,需要重寫writeObject()和readObject()方法

Parcelable接口

Parcelable接口无蜂,只要實現(xiàn)這個接口,一個類的對象就可以實現(xiàn)序列化,并通過Intent和Binder傳遞琉朽。
首先說一下Parcel,內(nèi)部包裝了可序列化的數(shù)據(jù),可以在Binder中自由傳輸,在序列化過程中峡钓,需要實現(xiàn)的功能有序列化、反序列化和功能描述辈赋。
序列化功能由writeToParcel()完成,最終通過Parcel的一系列write方法來完成。
反序列化功能由CREATOR完成鸦泳,其內(nèi)部標明了如何創(chuàng)建序列化對象和數(shù)組,并通過Parcel的一些列read方法來完成
內(nèi)容描述功能由describeContents方法完成鼎姐,幾乎所有情況這個方法都應該返回0钾麸,僅當當前對象中存在文件描述符時,返回1


Parcelable方法說明

Serializable和Parcelable的區(qū)別

  • Serializable是Java中的序列化接口炕桨,使用簡單但是開銷大饭尝,序列化和反序列化過程需要大量I/O。會創(chuàng)建大量的臨時變量献宫,從而引起頻繁GC
  • Parcelable是Android中的序列化方式钥平,缺點是使用稍微麻煩點,但是效率高姊途。主要用在內(nèi)存序列化上涉瘾,通過Parcelable將對象序列化到存儲設備中或者將對象序列化過后通過網(wǎng)絡傳輸,但是這個過程稍微復雜捷兰,所以這兩種情況推薦使用Serializable

Binder(使用和上層原理)

直觀來說立叛,Binder是Android的一個類,實現(xiàn)了Binder接口贡茅。從IPC角度來說秘蛇,Binder是Android中的一種跨進程通信方式。
Android開發(fā)中友扰,Binder主要用于Service中彤叉,包括AIDL和Messenger庶柿,其中普通的Service中不涉及進程通信村怪,就比較簡單,而Messenger底層是AIDL浮庐,所以針對AIDL來講解Binder

創(chuàng)建AIDL文件后甚负,系統(tǒng)會自動生成一個對應的Java類,其中包含兩個核心實現(xiàn)類审残,內(nèi)部stub類和stub的內(nèi)部類Proxy梭域,這兩個類的每個方法含義詳解如下:

  • DESCRIPTOR:Binder的唯一標識,一般用當前Binder的類名表示
  • asInterface(android.os.IBinder obj):用于將服務器的Binder對象轉(zhuǎn)換成客戶端所需AIDL接口類型對象搅轿,這種轉(zhuǎn)換過程是區(qū)分進程的病涨,如果客戶端和服務器位于統(tǒng)一進程,那么此方法返回的就是服務器端的Stub對象本身璧坟,否則就是返回系統(tǒng)封裝的Stub.Proxy對象
  • asBinder:用于返回當前Binder對象
  • onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flag):此方法運行在服務端的Binder線程中既穆,當服務器發(fā)起跨進程請求時赎懦,遠程請求會通過系統(tǒng)底層封裝后交由此方法處理。code用于確定客戶端所請求的目標方法是什么幻工,接著從data中取出目標方法所需參數(shù)励两,然后執(zhí)行目標方法,執(zhí)行完成后返回值寫入reply中囊颅。如果此方法返回false当悔,那么客戶端請求失敗
  • Proxy#XXX方法:運行在客戶端,當客戶端遠程調(diào)用此方法時:內(nèi)部會首先創(chuàng)建該方法所需要的輸入型Parcel對象_data踢代、輸出型Parcel對象_reply和返回值對象盲憎,然后將參數(shù)信息寫入_data中(如果有參數(shù)的話),接著調(diào)用onTransact()發(fā)起RPC請求(遠程過程調(diào)用)奸鬓,同時當前線程掛起焙畔;然后服務器onTransact()方法調(diào)用,直到RPC返回后當前線程繼續(xù)執(zhí)行串远。
注意:當客戶端發(fā)起遠程請求時宏多,由于當前線程會被掛起直至服務端進程喚醒并返回數(shù)據(jù),所以如果遠程方法很耗時澡罚,那么不能在UI線程中發(fā)起遠程請求伸但;由于服務器的Binder方法運行在Binder線程池中,所以不管Binder方法是否耗時都應采用同步的方式實現(xiàn)
Binder工作機制

Binder設置死亡代理

1留搔、首先聲明一個DeathRecipient對象更胖,DeathRecipient是一個接口,內(nèi)部只有一個方法binderDied隔显,當binder死亡時却妨,就會調(diào)用此方法,然后移除之前的Binderd代理并重新綁定遠程服務括眠。
2彪标、然后在客戶端綁定遠程服務后,給binder設置死亡代理:binder.linkTodeath(DeathRecipient, 標志位)
這樣設置好過后掷豺,當Binder死亡過后捞烟,就可以收到通知;另外還可以通過Binder的isBinderAlive()判斷Binder是否死亡当船。

Android中的IPC方式

1题画、Bundle

四大組件中Activity、Service德频、Receiver都支持在Intent中傳遞Bundle數(shù)據(jù)苍息,由于Bundle實現(xiàn)了Parcelable接口,所以可以在不同進程間傳遞。
Bundle支持的數(shù)據(jù)類型:基本數(shù)據(jù)類型竞思,實現(xiàn)了Parcelable接口和Serializable接口的對象桌粉,以及Android支持的特殊對象。

2衙四、文件共享

文件共享也是一種進程間的通信方式铃肯,兩個進程通過讀寫同一文件來交換數(shù)據(jù)。Windows上传蹈,一個文件如果被加了排斥鎖就會導致其他線程無法訪問其數(shù)據(jù)押逼,而Android基于Linux,并沒有對并非讀寫文件有所限制惦界。
文件共享方式共享數(shù)據(jù)對文件格式?jīng)]有具體要求隐绵,只要讀寫雙方約定數(shù)據(jù)格式即可搀庶。這種方式也是有局限性的,比如說:并發(fā)讀寫時,獲取的數(shù)據(jù)可能不是最新的潭千。因此需要妥善處理并發(fā)讀寫的問題友驮。
SharedPreference是個特例疼鸟,在多進程下殴蓬,讀寫操作就會變得不可靠,面對高并發(fā)的讀寫訪問就可能丟失數(shù)據(jù)狂窑。因此不建議在進程通信中使用SharedPreference

3媳板、Messenger

Messenger可以在不同進程中傳遞Message對象,在Message中放入需要傳遞的數(shù)據(jù)泉哈。
Messenger是一種輕量級的IPC方案蛉幸,底層實現(xiàn)是AIDL,對AIDL進行了封裝丛晦。
實現(xiàn)Messenger步驟奕纫,分為客戶端和服務器端:

  • 服務端進程
    服務端創(chuàng)建一個Service來處理客戶端的連接請求,同時創(chuàng)建一個Handler并通過它創(chuàng)建一個Messenger對象烫沙,然后再Service的onBind方法中返回這個Messenger對象底層的Binder即可匹层。
  • 客戶端進程
    客戶端進程首先綁定服務端的Service,綁定成功后用服務端返回的IBinder對象創(chuàng)建一個Messenger斧吐,通過這個Messenger向服務器端發(fā)送消息又固,消息類型為Message對象仲器。如果需要服務端回應煤率,則需要在客戶端創(chuàng)建一個Handler,并創(chuàng)建一個新的Messenger乏冀,并把這個Messenger對象通過Message的replyTo參數(shù)傳遞給服務端蝶糯,服務端通過這個replyTo就可以回應客戶端。


    Messenger工作原理

4辆沦、AIDL

AIDL實現(xiàn)進程通信流程分為客戶端和服務端:

  • 1昼捍、服務端
    服務端創(chuàng)建一個Service監(jiān)聽客戶端的連接請求识虚,然后創(chuàng)建一個AIDL文件,將暴露給客戶端的接口在這個AIDL文件中聲明妒茬,最后在Service中實現(xiàn)這個接口
  • 2担锤、客戶端
    綁定服務端的Service,綁定成功后乍钻,將服務端返回的Binder對象轉(zhuǎn)換成AIDL接口所屬類型肛循,然后就可以調(diào)用AIDL中的方法。
  • 3银择、AIDL接口的創(chuàng)建
    在AIDL文件中多糠,AIDL所支持的數(shù)據(jù)類型:
    (1)基本數(shù)據(jù)類型
    (2)String和CharSequence
    (3)List:只支持ArrayList,里面每個元素都必須能夠被AIDL支持
    (4)Map:只支持HashMap浩考,里面的每個元素都必須被AIDL支持夹孔,包括key和value
    (5)Parcelable:所有實現(xiàn)了Parcelable的對象
    (6)AIDL:所有AIDL接口本身也可以在AIDL中使用
    后續(xù)兩種數(shù)據(jù)需要顯示的import導入。

5析孽、使用ContentProvider

ContentProvider是Android專門提供用于不同進程間數(shù)據(jù)共享的方式搭伤,底層實現(xiàn)同樣是Binder
ContentProvider的使用參考——Android第一行代碼

6、使用Socket

Socket稱為套接字袜瞬,網(wǎng)絡通信中的概念闷畸,分為流式套接字和用戶數(shù)據(jù)報套接字也就是TCP和UDP

Binder連接池

AIDL使用大致流程:首先創(chuàng)建一個Service和AIDL接口,接著創(chuàng)建一個類繼承自AIDL接口中的Stub類并實現(xiàn)Stub中的抽象方法吞滞,在Service的onBind方法中返回這個類的對象佑菩,然后客戶端就可以綁定服務端的Service,建立連接后就可以訪問遠程服務端的方法了裁赠。
Binder連接池的主要作用:將每個業(yè)務模塊的Binder請求統(tǒng)一轉(zhuǎn)發(fā)到遠程Service中執(zhí)行殿漠,從而避免了重復創(chuàng)建Service的過程。


Binder連接池的工作原理

選擇合適的IPC方式

IPC方式的優(yōu)缺點和適用場景
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末佩捞,一起剝皮案震驚了整個濱河市绞幌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌一忱,老刑警劉巖莲蜘,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異帘营,居然都是意外死亡票渠,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門芬迄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來问顷,“玉大人,你說我怎么就攤上這事《耪” “怎么了肠骆?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長塞耕。 經(jīng)常有香客問我蚀腿,道長,這世上最難降的妖魔是什么扫外? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任唯咬,我火速辦了婚禮,結(jié)果婚禮上畏浆,老公的妹妹穿的比我還像新娘胆胰。我一直安慰自己,他們只是感情好刻获,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布蜀涨。 她就那樣靜靜地躺著,像睡著了一般蝎毡。 火紅的嫁衣襯著肌膚如雪厚柳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天沐兵,我揣著相機與錄音别垮,去河邊找鬼。 笑死扎谎,一個胖子當著我的面吹牛碳想,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播毁靶,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼胧奔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了预吆?” 一聲冷哼從身側(cè)響起龙填,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎拐叉,沒想到半個月后岩遗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡凤瘦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年宿礁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片廷粒。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡窘拯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出坝茎,到底是詐尸還是另有隱情涤姊,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布嗤放,位于F島的核電站思喊,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏次酌。R本人自食惡果不足惜恨课,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望岳服。 院中可真熱鬧剂公,春花似錦、人聲如沸吊宋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽璃搜。三九已至拖吼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間这吻,已是汗流浹背吊档。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留唾糯,地道東北人怠硼。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像移怯,于是被迫代替她去往敵國和親拒名。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容