Android進(jìn)程間通信

1、進(jìn)程和線程的概念:

在我的理解中乘凸,進(jìn)程是一段被操作系統(tǒng)執(zhí)行的指令集厕诡,操作系統(tǒng)在對(duì)資源>進(jìn)行分配和調(diào)度時(shí),進(jìn)程是基本單位翰意,進(jìn)程其實(shí)就是一個(gè)程序木人。而線程是操作系統(tǒng)調(diào)度的最小單元信柿。進(jìn)程可以包含多個(gè)線程冀偶,多個(gè)線程可共享進(jìn)程中的資源,另外線程的創(chuàng)建代價(jià)比線程要小

2渔嚷、多進(jìn)程的應(yīng)用場(chǎng)景:

通常需要用到多進(jìn)程的是进鸠,有常駐后臺(tái)的應(yīng)用,例如音樂(lè)播放器的后臺(tái)播放服務(wù)形病,健身跑步的計(jì)算步數(shù)和跑步路徑模塊等客年,這些模塊需要脫離界面運(yùn)行霞幅,而且需要長(zhǎng)時(shí)間的在系統(tǒng)中運(yùn)行,所以放在獨(dú)立的進(jìn)程中執(zhí)行是比較好的選擇量瓜。另外一種就是司恳,如果一些應(yīng)用很大,需要拆分模塊绍傲,為了增加應(yīng)用的內(nèi)存用量扔傅,就需要開(kāi)啟多個(gè)進(jìn)程來(lái)擴(kuò)大應(yīng)用的內(nèi)存用量,同時(shí)烫饼,將應(yīng)用模塊化猎塞,也更有利于解耦

3、實(shí)現(xiàn)多進(jìn)程的方式:

在android中實(shí)現(xiàn)多進(jìn)程有兩種方式杠纵,一種是在AndroidManifest文件中給組件設(shè)置android:process屬性荠耽,這樣,這個(gè)組件就運(yùn)行在設(shè)置的進(jìn)程中了比藻,另外一種就是利用jni在native層fork一個(gè)新的進(jìn)程出來(lái)

4铝量、android:process屬性的設(shè)置方式:

設(shè)置方式有兩種,一種是以“:xxx”的方式設(shè)置银亲,這種方式代表該進(jìn)程是應(yīng)用的私有進(jìn)程款违,其他應(yīng)用的組件不可在該進(jìn)程運(yùn)行,另外一種就是以“xxx.xx.xx”類似包名的方式來(lái)設(shè)置群凶,這種方式設(shè)置的進(jìn)程是全局的進(jìn)程插爹,其他應(yīng)用的組件也可以在該進(jìn)程上面運(yùn)行,但是shareUID必須一樣才可以

5请梢、在多進(jìn)程開(kāi)發(fā)中會(huì)遇到的問(wèn)題:

1赠尾、靜態(tài)成員和單例模式完全失效:因?yàn)橄到y(tǒng)會(huì)為每個(gè)進(jìn)程分配獨(dú)立的虛擬機(jī),不同的虛擬機(jī)會(huì)有不同的內(nèi)存空間毅弧,這會(huì)導(dǎo)致不同的虛擬機(jī)訪問(wèn)同一個(gè)類的對(duì)象會(huì)產(chǎn)生多個(gè)副本气嫁,我們修改其中一個(gè)副本只會(huì)影響當(dāng)前進(jìn)程,因此够坐,靜態(tài)成員和單例模式就會(huì)完全失效

2寸宵、線程同步機(jī)制會(huì)完全失效:既然是不同的內(nèi)存空間,那鎖的就不是同一個(gè)對(duì)象元咙,因此無(wú)法保證線程同步

3梯影、Sharedpreferences的可靠性下降:因?yàn)镾haredPreferences不支持兩個(gè)進(jìn)程同時(shí)執(zhí)行寫(xiě)操作

3、Application會(huì)被多次創(chuàng)建:不同的進(jìn)程有不同的虛擬機(jī)庶香,當(dāng)啟動(dòng)一個(gè)新的進(jìn)程時(shí)甲棍,相當(dāng)于一個(gè)應(yīng)用的啟動(dòng)過(guò)程,那么當(dāng)然赶掖,就會(huì)創(chuàng)建一個(gè)新的Application

6感猛、使用Serializable時(shí)需要注意的問(wèn)題:

在實(shí)現(xiàn)Serializable的過(guò)程中七扰,雖然serialVersionUID不寫(xiě)是可以,但是這樣可能會(huì)造成在反序列化的過(guò)程失敗陪白,因?yàn)檫@個(gè)serialVersionUID在序列化的過(guò)程中會(huì)被存儲(chǔ)進(jìn)去颈走,在反序列化的時(shí)候會(huì)先比較對(duì)象中的serialVersionUID是否與類中的serialVersionUID相同,如果在類中沒(méi)有設(shè)置這個(gè)值咱士,那么系統(tǒng)會(huì)自動(dòng)計(jì)算hash值疫鹊,而如果這個(gè)類的結(jié)構(gòu)發(fā)生了改變,那么這個(gè)自動(dòng)計(jì)算的hash值就會(huì)重新計(jì)算司致,就會(huì)造成反序列化的失敗拆吆。因此,設(shè)置這個(gè)值的意義在于盡量讓反序列化可以成功脂矫,就算有時(shí)候這個(gè)類已經(jīng)發(fā)生了部分改變枣耀。另外一個(gè)就是靜態(tài)成員不參與序列化,使用transient關(guān)鍵字標(biāo)記的成員不參與序列化

7庭再、Serializable與Parcelable的區(qū)別:

Parcelable是為了Android平臺(tái)而定制的捞奕,它的操作稍微復(fù)雜,但是效率很高拄轻,因此在內(nèi)存的序列化上推薦使用Parcelable颅围,而Serializable因?yàn)樵谛蛄谢瘯r(shí)需要進(jìn)行大量的IO操作,因此雖然操作簡(jiǎn)單恨搓,但是開(kāi)銷很大院促,因此,在將對(duì)象序列化到存儲(chǔ)設(shè)備中或者在網(wǎng)絡(luò)中傳輸就推薦使用Serializable

8斧抱、實(shí)現(xiàn)多進(jìn)程間通信的方式

實(shí)現(xiàn)多進(jìn)程間的通信有很多種方式常拓,1、利用Bundle進(jìn)行數(shù)據(jù)的傳遞辉浦,它簡(jiǎn)單易用弄抬,但是只支持Bundle支持的數(shù)據(jù)類型,推薦在四大組件的進(jìn)程通信可以使用它宪郊。2掂恕、文件共享,這種方式也比較簡(jiǎn)單易用弛槐,但是這種方式不適合多并發(fā)的場(chǎng)景懊亡,而且無(wú)法進(jìn)行進(jìn)程間的即時(shí)通信。3丐黄、Messenger斋配。這種方式的底層是利用AIDL實(shí)現(xiàn)的孔飒,支持一對(duì)多的串行通信灌闺,支持低并發(fā)的即時(shí)通信艰争。3、ContentProvider桂对,ContentProvider的底層利用Binder實(shí)現(xiàn)甩卓,天生支持跨進(jìn)程通信,但是它只適合用來(lái)作為數(shù)據(jù)共享蕉斜。4逾柿、Socket,這種方式通過(guò)網(wǎng)絡(luò)傳輸字節(jié)流也可以實(shí)現(xiàn)跨進(jìn)程通信宅此,但實(shí)現(xiàn)稍微負(fù)責(zé)机错,適合網(wǎng)絡(luò)間的數(shù)據(jù)交換。5父腕、AIDL弱匪,最后一種,也是最常用的一種方式璧亮,功能強(qiáng)大萧诫,下面會(huì)詳細(xì)介紹

9、AIDL的一些理解

AIDL(Android Interface Difinition Language)是一種Android種獨(dú)有的定義語(yǔ)言枝嘶,它的主要作用是為了簡(jiǎn)化跨進(jìn)程通信代碼的編寫(xiě)帘饶,在編譯階段,我們編寫(xiě)的AIDL文件會(huì)生成相應(yīng)的跨進(jìn)程代碼群扶,簡(jiǎn)單來(lái)說(shuō)及刻,它就是一種簡(jiǎn)化的工具,沒(méi)有AIDL竞阐,我們一樣可以編寫(xiě)出跨進(jìn)程代碼提茁,只是會(huì)稍微繁瑣一點(diǎn)

AIDL只會(huì)接受基本的數(shù)據(jù)類型(通過(guò)實(shí)驗(yàn)short還不行),String和CharSequence類型馁菜,然后如果是自定義的對(duì)象茴扁,需要實(shí)現(xiàn)Parcelable接口,并且需要在AIDL文件中聲明出來(lái)汪疮,這樣才可以使用峭火,當(dāng)然也可以用集合(ArrayList,HashMap)作為參數(shù),但是集合中的元素也必須是AIDL支持的類型智嚷。另外需要注意的就是AIDL文件中的方法參數(shù)卖丸,是有一個(gè)數(shù)據(jù)流向的,通過(guò)in盏道,out稍浆,inout三個(gè)標(biāo)識(shí)來(lái)確定,如果參數(shù)設(shè)置為in,那么數(shù)據(jù)的流向就是客戶端->服務(wù)器(意思就是客戶端傳遞給服務(wù)器的信息衅枫,服務(wù)器可以收到嫁艇,但是服務(wù)器如果改動(dòng)了這個(gè)傳遞的對(duì)象逆粹,客戶端中的原對(duì)象是不會(huì)跟著發(fā)生改變的)空厌,如果參數(shù)設(shè)置為out咽袜,那么數(shù)據(jù)的流向就是服務(wù)端->客戶端(意思就是客戶端傳遞給服務(wù)端的參數(shù)挺庞,服務(wù)端是無(wú)法收到的退敦,但是服務(wù)端改動(dòng)了這個(gè)對(duì)象的內(nèi)容蹋凝,在客戶端的原對(duì)象是會(huì)跟著改變的)年鸳,如果參數(shù)設(shè)置為inout霍掺,那就代表著雙向流動(dòng)感凤,但是一般情況不提倡這樣設(shè)置悯周,因?yàn)闀?huì)增加開(kāi)銷

10、使用AIDL需要注意的地方:

在使用AIDL的過(guò)程中陪竿,會(huì)有一種情形队橙,就是當(dāng)服務(wù)端處理了一些業(yè)務(wù),需要主動(dòng)通知客戶端萨惑,而不是等待客戶端發(fā)起請(qǐng)求才去響應(yīng)捐康,那么這個(gè)時(shí)候就需要觀察者模式了,這個(gè)時(shí)候我們需要注冊(cè)監(jiān)聽(tīng)服務(wù)端的狀態(tài)庸蔼,這個(gè)時(shí)候服務(wù)端需要保存客戶端的監(jiān)聽(tīng)解总,因此,可能會(huì)有并發(fā)的情形姐仅,因此推薦使用RemoteCallbackList進(jìn)行保存花枫。另外就是有時(shí)候服務(wù)端進(jìn)程被kill掉,這時(shí)候會(huì)造成鏈接失敗掏膏,因此我們需要通過(guò)linkToDeath來(lái)綁定服務(wù)端劳翰,如果服務(wù)端進(jìn)程殺死,客戶端可以收到響應(yīng)馒疹,可以進(jìn)行重連操作佳簸。

11、AIDL的實(shí)際操作:

在實(shí)際開(kāi)發(fā)過(guò)程中颖变,我們?nèi)绻泻芏嗄K都需要用到AIDL的話生均,那么不可能每個(gè)模塊開(kāi)啟一個(gè)服務(wù)進(jìn)程來(lái)處理,這樣造成的系統(tǒng)資源損耗是巨大的腥刹,因此我們需要利用Binder連接池來(lái)作為中間媒介马胧,來(lái)鏈接各個(gè)AIDL的處理,下面的例子來(lái)演示相關(guān)實(shí)現(xiàn)

11.1 第一步

首先衔峰,創(chuàng)建兩個(gè)AIDL文件IPlayMedia.aidl和IMonitorDevice.aidl佩脊,代碼如下:

interface IPlayMedia {
    void play(in String path);
    void puase();
    void stop();
    String getCurrentMusicName();
}

interface IMonitorDevice {
    void monitor(int a);
}

11.2 第二步

實(shí)現(xiàn)AIDL接口蛙粘,代碼如下:

// IPlayMedia接口實(shí)現(xiàn)
public class PlayMediaImpl extends IPlayMedia.Stub{

    @Override
    public void play(String path) throws RemoteException {
        Log.e("TAG","播放音樂(lè):"+path);
    }

    @Override
    public void puase() throws RemoteException {
        Log.e("TAG","暫停播放");
    }

    @Override
    public void stop() throws RemoteException {
        Log.e("TAG","停止播放");
    }

    @Override
    public String getCurrentMusicName() throws RemoteException {
        Log.e("TAG","獲取當(dāng)前歌曲名稱");
        return "七里香";
    }
}

// IMonitorDevice的實(shí)現(xiàn)
public class MonitorDeviceImpl extends IMonitorDevice.Stub {

    @Override
    public void monitor(int a) throws RemoteException {
        Log.e("TAG","監(jiān)控方法實(shí)現(xiàn)");
    }
}

11.3 第三步

接下來(lái)需要?jiǎng)?chuàng)建一個(gè)BinderPool連接池AIDL接口,這個(gè)接口是直接與服務(wù)端進(jìn)程的服務(wù)交互的

interface BinderPool {
    IBinder queryBinder(int binderCode);
}

11.4 第四步

接下來(lái)創(chuàng)建一個(gè)服務(wù)AIDLService,設(shè)置android:process屬性威彰,讓其可以在獨(dú)立的進(jìn)程運(yùn)行出牧,先不做任何的實(shí)現(xiàn),接著抱冷,創(chuàng)建BinderPoolUtils工具類崔列,代碼如下:

public class BinderPoolUtils {

    public static final int BINDER_PLAY_MEDIA = 1;
    public static final int BINDER_MONITOR_DEVICE = 2;
    public static volatile BinderPoolUtils mInstance = null;

    private Context mContext;
    private test.com.testpoj.BinderPool mBinderPool;
    private CountDownLatch mConnectBinderPoolDownLatch;

    /**
     * 單例模式
     */
    public static BinderPoolUtils getInstance(Context context) {
        if (mInstance == null) {
            synchronized (BinderPoolUtils.class) {
                if (mInstance == null) {
                    mInstance = new BinderPoolUtils(context);
                }
            }
        }
        return mInstance;
    }

    /**
     * 查詢對(duì)應(yīng)的Binder對(duì)象
     */
    public IBinder queryBinder(int binderCode) {
        IBinder binder = null;
        try {
            if (mBinderPool != null) {
                binder = mBinderPool.queryBinder(binderCode);
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return binder;
    }

    /**
     * 構(gòu)造方法私有化
     */
    private BinderPoolUtils(Context context) {
        mContext = context;
        connectBinderPoolService();
    }

    /**
     * 綁定服務(wù)
     */
    private synchronized void connectBinderPoolService() {
        mConnectBinderPoolDownLatch = new CountDownLatch(1);
        Intent intent = new Intent(mContext, AIDLService.class);
        mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
        try {
            mConnectBinderPoolDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBinderPool = test.com.testpoj.BinderPool.Stub.asInterface(service);
            try {
                mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            mConnectBinderPoolDownLatch.countDown();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0);
            mBinderPool = null;
            connectBinderPoolService();
        }
    };

    /**
     * BinderPool鏈接池的實(shí)現(xiàn)
     */
    public static class BinderPoolImpl extends test.com.testpoj.BinderPool.Stub {

        @Override
        public IBinder queryBinder(int binderCode) throws RemoteException {
            IBinder binder = null;
            switch (binderCode) {
                case BINDER_PLAY_MEDIA:
                    binder = new PlayMediaImpl();
                    break;
                case BINDER_MONITOR_DEVICE:
                    binder = new MonitorDeviceImpl();
                    break;
                default:
                    break;
            }
            return binder;
        }
    }
}

有了上面的工具類梢褐,我們就可以在AIDLService中的onBinder方法中返回BinderPoolImpl的實(shí)現(xiàn)旺遮,然后我們調(diào)用的時(shí)候就可以這樣來(lái)調(diào)用:

  BinderPoolUtils utils = BinderPoolUtils.getInstance(this);
  IBinder playBinder = utils.queryBinder(BinderPoolUtils.BINDER_PLAY_MEDIA)
  mPlayManager = IPlayMedia.Stub.asInterface(playBinder);

這樣我們就可以調(diào)用IPlayMedia接口中的方法了

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市盈咳,隨后出現(xiàn)的幾起案子耿眉,更是在濱河造成了極大的恐慌,老刑警劉巖鱼响,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸣剪,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡丈积,警方通過(guò)查閱死者的電腦和手機(jī)筐骇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)江滨,“玉大人铛纬,你說(shuō)我怎么就攤上這事』;” “怎么了告唆?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)晶密。 經(jīng)常有香客問(wèn)我擒悬,道長(zhǎng),這世上最難降的妖魔是什么稻艰? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任懂牧,我火速辦了婚禮,結(jié)果婚禮上尊勿,老公的妹妹穿的比我還像新娘归苍。我一直安慰自己,他們只是感情好运怖,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布拼弃。 她就那樣靜靜地躺著,像睡著了一般摇展。 火紅的嫁衣襯著肌膚如雪吻氧。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,816評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音盯孙,去河邊找鬼鲁森。 笑死,一個(gè)胖子當(dāng)著我的面吹牛振惰,可吹牛的內(nèi)容都是我干的歌溉。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼骑晶,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼痛垛!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起桶蛔,我...
    開(kāi)封第一講書(shū)人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤匙头,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后仔雷,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蹂析,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年碟婆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了电抚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡竖共,死狀恐怖蝙叛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肘迎,我是刑警寧澤甥温,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站妓布,受9級(jí)特大地震影響姻蚓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜匣沼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一狰挡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧释涛,春花似錦加叁、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至窖认,卻和暖如春豫柬,著一層夾襖步出監(jiān)牢的瞬間告希,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工烧给, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留燕偶,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓础嫡,卻偏偏與公主長(zhǎng)得像指么,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子榴鼎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

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