Android進(jìn)程間通信

作者簡(jiǎn)介? 原創(chuàng)微信公眾號(hào)郭霖 WeChat ID: guolin_blog

明天就是周末了喉恋,這里提前祝大家周末愉快麻掸!

本篇來(lái)自夏雨的投稿,詳細(xì)地介紹了跨進(jìn)程通信的兩種方案斑举,希望能夠幫助到大家搅轿。

夏雨的博客地址:

http://blog.csdn.net/yulyu

前言

進(jìn)程間通信(Inter-Process Communication),簡(jiǎn)稱(chēng) IPC,就是指進(jìn)程與進(jìn)程之間進(jìn)行通信.一般來(lái)說(shuō),一個(gè)app只有一個(gè)進(jìn)程,但是可能會(huì)有多個(gè)線(xiàn)程,所以我們用得比較多的是多線(xiàn)程通信,比如 Handler,AsyncTask.

但是在一些特殊的情況下,我們app會(huì)需要多個(gè)進(jìn)程,或者是我們?cè)谶h(yuǎn)程服務(wù)調(diào)用時(shí),就需要跨進(jìn)程通信了

設(shè)置多進(jìn)程

Android設(shè)置多進(jìn)程的步驟很簡(jiǎn)單,只用在清單文件中為四大組件加上 process 屬性:

( :messager 最終的進(jìn)程名會(huì)變成 包名+:messager)

雖然多進(jìn)程設(shè)置起來(lái)很簡(jiǎn)單,但是使用的時(shí)候卻會(huì)有一系列的問(wèn)題:

兩個(gè)進(jìn)程對(duì)應(yīng)的是不同的內(nèi)存區(qū)域

1.Application對(duì)象會(huì)創(chuàng)建多次

2.靜態(tài)成員不共用

3.同步鎖失效

4.單例模式失效

5.數(shù)據(jù)傳遞的對(duì)象必須可序列化

可序列化

進(jìn)程間通信傳遞的對(duì)象是有嚴(yán)格要求的,除了基本數(shù)據(jù)類(lèi)型,其他對(duì)象要想可以傳遞,必須可序列化,Android實(shí)現(xiàn)可序列化一般是通過(guò)實(shí)現(xiàn) Serializable 或者是 Parcelable

如果你在進(jìn)程通信中不需要傳非基本數(shù)據(jù)類(lèi)型的對(duì)象,那么你可以不了解序列化,但是可序列化是進(jìn)程間通信的基礎(chǔ),所以還是建議不了解的朋友先熟悉一下

筆者之前介紹過(guò)序列化的相關(guān)知識(shí),這里就不重復(fù)介紹了:

序列化–Serializable與Parcelable

http://blog.csdn.net/yulyu/article/details/56481665

通信

跨進(jìn)程通信的方法有很多,比如通過(guò) Intent傳遞,通過(guò) AIDL 以及 Messager通信,通過(guò) socket通信,這里主要介紹的是基于 Binder 的 AIDL 和 Messager。

Intent

Intent 進(jìn)行數(shù)據(jù)的傳遞是我們平時(shí)最常用的,他的原理其實(shí)是對(duì)于 Binder 的封裝,但是他只能做到單向的數(shù)據(jù)傳遞,所以并不能很好的實(shí)現(xiàn)跨進(jìn)程通信,我們這里就不展開(kāi)來(lái)介紹了

Messenger

Messenger 的底層也是基于 Binder 的,其實(shí)應(yīng)該說(shuō)他是在 AIDL 的基礎(chǔ)上封裝了一層.

一般來(lái)說(shuō)安卓中使用 Binder 主要是通過(guò)綁定服務(wù)(bindService),服務(wù)端(這里指的不是后臺(tái),是指其中一個(gè)進(jìn)程)主要是運(yùn)行 Service,客戶(hù)端通過(guò) bindService 獲取到相關(guān)的 Binder,Binder 就作為橋梁進(jìn)行跨進(jìn)程的通信.

這里我們先演示同一個(gè)應(yīng)用內(nèi)的多進(jìn)程通信

服務(wù)器端

首先我們先創(chuàng)建一個(gè)Service:

并在清單文件中配置他的進(jìn)程:

在 Service?里面創(chuàng)建一個(gè) Hander 用來(lái)接受消息:

在 Service?里面創(chuàng)建一個(gè) Messenger,并把 Handler 放入其中:

privatefinalstaticMessengermMessenger=newMessenger(mHandler);

重寫(xiě) onBind 方法,返回 Messenger 里面的 Binder:

publicIBinderonBind(Intentintent) {

returnmMessenger.getBinder();}

客戶(hù)端

創(chuàng)建一個(gè)對(duì)象實(shí)現(xiàn) ServiceConnection:

綁定服務(wù):

綁定服務(wù)后,會(huì)調(diào)用 ServiceConnection 的 onServiceConnected 方法,通過(guò) Messenger 發(fā)送消息,服務(wù)器端的 Handler 就能夠收到消息了:

這樣的話(huà)我們就能夠通過(guò) bindService 獲取到一個(gè)包含 Binder 的 Messenger 進(jìn)行通信了,但是我們目前只實(shí)現(xiàn)了客戶(hù)端對(duì)服務(wù)器端傳遞消息,那么服務(wù)器端如何對(duì)客戶(hù)端傳遞消息呢?

我們先對(duì)服務(wù)器端的代碼進(jìn)行修改,首先修改 Service 的 Handler:

接著我們?cè)诳蛻?hù)端也增加一個(gè) Handler 和 Messenger 來(lái)處理消息:

還有一個(gè)比較關(guān)鍵的地方,就是要在客戶(hù)端發(fā)送消息的時(shí)候把客戶(hù)端的 Messenger 通過(guò)消息傳送到服務(wù)器端

這樣一來(lái),服務(wù)器端和客戶(hù)端就能很好的實(shí)現(xiàn)跨進(jìn)程通信了.

如果需要傳送數(shù)據(jù)的話(huà),可以通過(guò) Bundle 設(shè)置數(shù)據(jù),除了基本數(shù)據(jù)類(lèi)型,還可以通過(guò)消息傳送可序列化的對(duì)象

發(fā)送方:

接收方:

弊端

上面我們已經(jīng)實(shí)現(xiàn)了跨進(jìn)程通信,但是這里面其實(shí)是有弊端的,服務(wù)端處理客戶(hù)端的消息是串行的,必須一個(gè)一個(gè)來(lái)處理,所以如果是并發(fā)量比較大的時(shí)候,通過(guò) Messenger 來(lái)通信就不太適合了

注意

上面演示的是應(yīng)用內(nèi)跨進(jìn)程通信,綁定服務(wù)可以通過(guò)顯示意圖來(lái)綁定,但是如果是跨應(yīng)用的進(jìn)程間通信,那么就需要用到隱式意圖了.這里有一點(diǎn)需要注意的就是,在 5.0 以后隱式意圖開(kāi)啟或者綁定 service 要 setPackage(Service的包名),不然會(huì)報(bào)錯(cuò)

AIDL

上面提到過(guò)通過(guò) Messenger 跨進(jìn)程不適合并發(fā)量大的情況,那么如果并發(fā)量大的話(huà),我們用什么來(lái)處理呢?那就可以通過(guò) AIDL 來(lái)進(jìn)行,這里是Google的描述:

Note: Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want?to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you?should create your interface by implementing a Binder or, if you want to perform IPC, but do not need to handle?multithreading, implement your interface using a Messenger. Regardless, be sure that you understand Bound Services before?implementing an AIDL.

主要意思就是你可以用 Messenger 處理簡(jiǎn)單的跨進(jìn)程通信,但是高并發(fā)量的要用AIDL

我們還是先演示一下同一個(gè)應(yīng)用內(nèi)的跨進(jìn)程通信.

服務(wù)端

首先我們創(chuàng)建一個(gè) Service:

然后在清單文件里面設(shè)置 Service 的進(jìn)程:

然后右鍵選擇新建 AIDL 文件,Android Studio就會(huì)幫你在你的aidl目錄的同名文件夾下面創(chuàng)建一個(gè)AIDL文件

在AIDL文件里面會(huì)有一個(gè)接口,并聲明了一個(gè)方法,那個(gè)方法主要是告訴你AIDL支持哪些數(shù)據(jù)類(lèi)型傳輸,所以我們把這個(gè)方法刪掉,我們?cè)僮约郝暶饕粋€(gè)方法,用于之后的調(diào)用

(注意:每次修改了AIDI文件后,需要同步一下才會(huì)生效,因?yàn)槊看瓮胶?Android Studio會(huì)在 項(xiàng)目/build/generated/source/aidl/debug 目錄下生成相應(yīng)的Java文件)

我們?cè)?Service 中創(chuàng)建一個(gè) Binder,并在 onBind 的時(shí)候返回:

客戶(hù)端

創(chuàng)建自定義一個(gè)類(lèi)實(shí)現(xiàn) ServiceConnection:

綁定服務(wù),當(dāng)綁定成功時(shí)會(huì)走 Connection的onServiceConnected 方法,并把 Binder 傳過(guò)來(lái)

在 onServiceConnected 方法里面通過(guò) asInterface 獲取服務(wù)器傳過(guò)來(lái)的對(duì)象,并調(diào)用服務(wù)端的方法

現(xiàn)在客戶(hù)端就可以調(diào)用 sell方法 來(lái)進(jìn)行跨進(jìn)程通信了,但目前只能傳輸基本數(shù)據(jù)類(lèi)型的數(shù)據(jù),那么如果想要傳其他數(shù)據(jù)呢?那么我們接著往下講:

通過(guò)AIDL傳送復(fù)雜數(shù)據(jù)

首先我們要知道AIDL支持那么數(shù)據(jù)類(lèi)型

1.基本數(shù)據(jù)類(lèi)型

2.實(shí)現(xiàn)了Parcelable接口的對(duì)象

3.List:只支持ArrayList,并且里面的元素需要時(shí)AIDL支持的

4.Map:只支持HashMap,并且里面的key和value都需要是被AIDL支持的

那么我們定義一個(gè)對(duì)象 Product 實(shí)現(xiàn) Parcelable 接口,Product 我們?cè)O(shè)置了兩個(gè)字段:

接著我們需要在 aidl文件夾 的相同目錄創(chuàng)建一個(gè)相同文件名的 aidl文件

注意:這里我們是要通過(guò) new File 的方式創(chuàng)建,并且要自己輸入文件后綴aidl,如果你用new AIDL的方式創(chuàng)建的話(huà),他會(huì)提示你 Interface Name must be unique

接著我們需要在這個(gè) aidl文件 里面輸入包名,并且聲明一下變量為 Parcelable類(lèi)型(注意:這里聲明的時(shí)候是用小寫(xiě)的 parcelable)

//Product.aidl

packagecom.xiayu.aidldemo;parcelableProduct;

我們回到之前的 IShop.aidl,刪掉之前的 sell方法,并再創(chuàng)建兩個(gè)新方法:

這里有三個(gè)需要注意的地方

(1).IShop.aidl雖然跟Product.aidl在同一個(gè)包下,但是這里還是需要手動(dòng)import進(jìn)來(lái)

(2).這里聲明方法時(shí),需要在參數(shù)前面增加一個(gè)tag,這個(gè)tag有三種,in,out,inout,這里表示的是這個(gè)參數(shù)可以支持的流向:

in:這個(gè)對(duì)象能夠從客戶(hù)端到服務(wù)器,但是作為返回值從服務(wù)器到客戶(hù)端的話(huà)數(shù)據(jù)不會(huì)傳送過(guò)去(不會(huì)為null,但是字段都沒(méi)有賦值)

out:這個(gè)對(duì)象能夠作為返回值從服務(wù)器到客戶(hù)端,但是從客戶(hù)端到服務(wù)器數(shù)據(jù)會(huì)為空(不會(huì)為null,但是字段都沒(méi)有賦值)

inout:能從客戶(hù)端到服務(wù)器,也可以作為返回值從服務(wù)器到客戶(hù)端

用一張圖來(lái)總結(jié):

(不要都設(shè)為inout,要看需求來(lái)設(shè)置,因?yàn)闀?huì)增加開(kāi)銷(xiāo))

(3).默認(rèn)實(shí)現(xiàn) Parcelable 的模版只支持 in ,如果需要需要支持 out 或 inout 需要手動(dòng)實(shí)現(xiàn) readFromParcel 方法:

現(xiàn)在就可以在客戶(hù)端中通過(guò) IShop 調(diào)用方法來(lái)進(jìn)行通信了

不同應(yīng)用間的多進(jìn)程通信(AIDL)

上面我們介紹了同一個(gè)應(yīng)用內(nèi)的進(jìn)程間通信,接下來(lái)我們就來(lái)介紹不同應(yīng)用之間的進(jìn)程間通信

服務(wù)器端

首先我們需要把 Product.java 放到aidl目錄相同名字的文件夾下(如果要提供服務(wù)給其他app,最好把需要的對(duì)象都放在aidl目錄下,這樣比較容易拷貝)

但是這個(gè)時(shí)候你運(yùn)行程序的話(huà),編譯會(huì)提示說(shuō)找不到 Product,那是因?yàn)锳ndroid Studio默認(rèn)會(huì)去java目錄下找,這時(shí)候需要在build.gradle文件 android{ } 中間增加一段代碼,讓aidl目錄里面的java文件也能被識(shí)別

接著我們?yōu)?Service?增加 intent-filter,這樣其他應(yīng)用才能通過(guò)隱式意圖綁定服務(wù),服務(wù)器端的修改就結(jié)束了

客戶(hù)端

我們需要?jiǎng)?chuàng)建一個(gè)新的應(yīng)用來(lái)作為客戶(hù)端,并且把服務(wù)器端的 aidl 目錄下的所有文件都拷貝過(guò)來(lái),這里要注意的就是里面的目錄不能改變,需要與以前一致:

點(diǎn)擊同步,Android Studio會(huì)自動(dòng)生成相應(yīng)的java文件供我們使用

這個(gè)時(shí)候我們需要通過(guò)隱式意圖來(lái)綁定服務(wù)了(注意:5.0以后隱式意圖開(kāi)啟或者綁定service要setPackage,不然會(huì)報(bào)錯(cuò))

mIntent.setAction("action.xiayu");mIntent.setPackage("com.xiayu.aidldemo");

接下來(lái)的操作就和之前一樣了,創(chuàng)建一個(gè)類(lèi)實(shí)現(xiàn) ServiceConnection:

綁定服務(wù)

bindService(mIntent, mXiayuConnection,BIND_AUTO_CREATE);

通過(guò) ServiceConnection 的 onServiceConnected 里面的 IBinder 進(jìn)行通信

解除綁定的時(shí)候釋放資源

這樣我們就可以通過(guò)獲得的IShop進(jìn)行不同應(yīng)用之間的進(jìn)程間通信了

最后再提幾點(diǎn)用到服務(wù)時(shí)需要注意的地方(很簡(jiǎn)單,但是有些人經(jīng)常會(huì)忽略這幾點(diǎn))

1:startService和stopService需要用同一個(gè)Intent對(duì)象

2:bindService和unbindService需要用同一個(gè)ServiceConnection對(duì)象

3:5.0以后隱式意圖開(kāi)啟或者綁定service要setPackage(包名)

完富玷。璧坟。。赎懦。雀鹃。。励两。黎茎。。当悔。傅瞻。。盲憎。嗅骄。。饼疙。溺森。。。儿惫。澡罚。

文章原創(chuàng)作者GuoLin 書(shū)籍推薦

郭林大神原創(chuàng)android 書(shū)籍:《第一行代碼 android》

淘寶鏈接: https://s.click.taobao.com/t?e=m%3D2%26s%3DgKUfuKdAZKocQipKwQzePOeEDrYVVa64K7Vc7tFgwiHjf2vlNIV67p2n%2BQBNMyE6Rku8%2Bpj6eJall3bs%2B3NRhNHnsKI%2BqxhyM0iVZhTFBom4YIorMPnmg8G0g2OJi%2FzmXHfenomYtn5EW9vzeG8LzfPUwktUBEmkxg5p7bh%2BFbQ%3D&pvid=10_106.6.161.154_3367_1490163222155

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市肾请,隨后出現(xiàn)的幾起案子留搔,更是在濱河造成了極大的恐慌,老刑警劉巖铛铁,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件隔显,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡饵逐,警方通過(guò)查閱死者的電腦和手機(jī)括眠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)倍权,“玉大人掷豺,你說(shuō)我怎么就攤上這事”∩” “怎么了当船?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)默辨。 經(jīng)常有香客問(wèn)我德频,道長(zhǎng),這世上最難降的妖魔是什么缩幸? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任壹置,我火速辦了婚禮,結(jié)果婚禮上表谊,老公的妹妹穿的比我還像新娘钞护。我一直安慰自己,他們只是感情好爆办,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布难咕。 她就那樣靜靜地躺著,像睡著了一般押逼。 火紅的嫁衣襯著肌膚如雪步藕。 梳的紋絲不亂的頭發(fā)上惦界,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天挑格,我揣著相機(jī)與錄音,去河邊找鬼沾歪。 笑死漂彤,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播挫望,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼立润,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了媳板?” 一聲冷哼從身側(cè)響起桑腮,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蛉幸,沒(méi)想到半個(gè)月后破讨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡奕纫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年提陶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匹层。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡隙笆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出升筏,到底是詐尸還是另有隱情撑柔,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布仰冠,位于F島的核電站乏冀,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏洋只。R本人自食惡果不足惜辆沦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望识虚。 院中可真熱鬧肢扯,春花似錦、人聲如沸担锤。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)肛循。三九已至铭腕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間多糠,已是汗流浹背累舷。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留夹孔,地道東北人被盈。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓析孽,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親只怎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子袜瞬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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