2.4 Android中的IPC方式(一)

1. 實(shí)現(xiàn)IPC(跨進(jìn)程)方法一 Bundle

Bundle可以通過Intent在跨進(jìn)程時(shí)帶過去,它支持基本數(shù)據(jù)類型,實(shí)現(xiàn)了Parcelable接口的對(duì)象停团,實(shí)現(xiàn)了Serializable接口的對(duì)象以及其他一些Android支持的特殊對(duì)象喊递。

2. 特殊場(chǎng)景

A進(jìn)程進(jìn)行一個(gè)計(jì)算,計(jì)算完成后啟動(dòng)B進(jìn)程的一個(gè)組件并把計(jì)算結(jié)果傳遞給B進(jìn)程蹬癌。問題是該結(jié)果不支持放入Bundle。
思考解決方式如下:A進(jìn)程啟動(dòng)B進(jìn)程的服務(wù)完成計(jì)算虹茶,B進(jìn)程的服務(wù)把計(jì)算結(jié)果給目標(biāo)組件逝薪。

3. 實(shí)現(xiàn)IPC(跨進(jìn)程)方法二 文件共享

兩個(gè)進(jìn)程讀寫同一文件可以實(shí)現(xiàn)跨進(jìn)程通信。windows上蝴罪,一個(gè)文件如果被加了排斥鎖將會(huì)導(dǎo)致其他進(jìn)程無法對(duì)其進(jìn)行訪問董济,包括讀寫。而Android是基于Linux的要门,使得其并發(fā)讀寫文件沒有限制感局。所以文件共享的方式要考慮并發(fā)問題。下面的代碼是MainActivity中序列化對(duì)象到文件暂衡,不同進(jìn)程的SecondActivity反序列化文件到對(duì)象询微。

// 序列化
try {
    User user = new User(110, "allen");
    File cache = new File(getCacheDir(), "cache.txt");
    if (!cache.exists()) {
        cache.createNewFile();
    }
    
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(cache.getAbsoluteFile()));
    out.writeObject(user);
    out.close();
    Log.e("aaa","---------"+user.toString());
} catch (IOException e) {
    e.printStackTrace();
}
// 反序列化
try {
    File cache = new File(getCacheDir(), "cache.txt");
    if (!cache.exists()) {
        cache.createNewFile();
    }
    
    ObjectInputStream in = new ObjectInputStream(new FileInputStream(cache.getAbsoluteFile()));
    User newUser = (User) in.readObject();
    in.close();
    Log.e("aaa","---------"+newUser.toString());
} catch (IOException e) {
    e.printStackTrace();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

文件類型沒有要求,比如txt的狂巢,xml的撑毛。但SharedPreferences是個(gè)例外,SharedPrefrences是Android提供的輕量級(jí)存儲(chǔ)方案唧领,它以鍵值對(duì)的方式來存儲(chǔ)數(shù)據(jù)藻雌,在底層實(shí)現(xiàn)上采用了xml文件來存儲(chǔ)。其目錄位于/data/data/packageName/shared_prefs目錄下斩个。從本質(zhì)上來說胯杭,SharedPreference也屬于文件的一種,但是對(duì)于系統(tǒng)對(duì)它的讀寫有一定的緩存策略受啥,即在內(nèi)存中會(huì)有一份SharedPreference文件的緩存做个。因此在多進(jìn)程模式下,系統(tǒng)對(duì)它的讀寫就變得不可靠滚局。因此不建議進(jìn)程間通信使用SharedPreference居暖。

3. Messenger簡介

Messanger可以翻譯為信使,顧名思義藤肢,通過它可以在不同的進(jìn)程中傳遞Message對(duì)象太闺。它是一種輕量級(jí)的IPC方案,它的底層實(shí)現(xiàn)了AIDL嘁圈。(書中說是根據(jù)構(gòu)造方法的寫法和aidl相似省骂,有些牽強(qiáng))蟀淮。
下面看下Messenger的代碼:

public final class Messenger implements Parcelable {
    private final IMessenger mTarget;

    public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }
    
    public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }
    
    public IBinder getBinder() {
        return mTarget.asBinder();
    }
    // ...
    
    public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }
}

重點(diǎn)還是IMessenger是個(gè)aidl接口。用everything搜一下可以搜到以下結(jié)果:

Paste_Image.png

4. 簡單Messenger跨進(jìn)程實(shí)現(xiàn)

服務(wù)端:

public class MessengerService extends Service {
    private Handler messengerHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0:
                    String text = msg.getData().getString("msg");
                    Log.e("aaa", text);
                    break;
            }
        }
    };
    private Messenger messenger = new Messenger(messengerHandler);

    public MessengerService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return messenger.getBinder();
    }
}

客戶端:

public class MessengerActivity extends AppCompatActivity {

    Messenger messenger;
    ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            messenger = new Messenger(service);
            // 發(fā)消息
            Message msg = Message.obtain();
            msg.what = 0;
            Bundle bundle = new Bundle();
            bundle.putString("msg", "hello, this is client.");
            msg.setData(bundle);
            try {
                messenger.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messenger);

        Intent intent = new Intent(this, MessengerService.class);
        bindService(intent, serviceConnection, BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(serviceConnection);
    }
}

Service定義在單獨(dú)的進(jìn)程中

<service
    android:name="._2activity.Messenger.MessengerService"
    android:enabled="true"
    android:exported="true"
    android:process=":remote" />

Messenger支持的數(shù)據(jù)類型實(shí)際是Message支持的數(shù)據(jù)類型钞澳,Message支持Bundle灭贷,所以適用性很強(qiáng)。

5. 實(shí)現(xiàn)客戶端發(fā)信息并且服務(wù)端響應(yīng)

上面的例子中服務(wù)端定義了接受消息的Messenger(也就是參數(shù)是Handler的)略贮,客戶端通過Binder拿到服務(wù)端的Messenger,然后用服務(wù)端的Messenger發(fā)消息給服務(wù)端仗岖。同樣逃延,服務(wù)端要回應(yīng),需要有客戶端接受消息的Messenger轧拄。
Activity中如下:

// 定義客戶端接受消息的Messenger
Messenger clientMessenger = new Messenger(new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        Log.e("aaa",msg.getData().getString("reply"));
    }
});
// 通過Message的replyto參數(shù)給服務(wù)端
// 發(fā)消息
Message msg = Message.obtain();
msg.what = 0;
Bundle bundle = new Bundle();
bundle.putString("msg", "hello, this is client.");
msg.setData(bundle);
// 把接收消息的Messenger通過Message的replyTo給服務(wù)端
msg.replyTo = clientMessenger;
messenger.send(msg);

服務(wù)端接收消息后揽祥,拿到客戶端的Messenger,再給客戶端發(fā)消息檩电。

private Handler messengerHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
            case 0:
                String text = msg.getData().getString("msg");
                Log.e("aaa", text);
                // 服務(wù)端回應(yīng)
                Messenger clientMessenger = msg.replyTo;
                Message message = Message.obtain();
                Bundle bundle = new Bundle();
                bundle.putString("reply","收到收到已收到");
                message.setData(bundle);
                try {
                    clientMessenger.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
        }
    }
};

6. 總結(jié)

Messenger很強(qiáng)大拄丰,它是實(shí)現(xiàn)輕量級(jí)IPC的方案。在普通開發(fā)中俐末,還可以用于Service調(diào)Activity中的方法料按,或者Activity調(diào)Service中的方法。之前說Activity調(diào)Service中的方法通過Binder卓箫,Service調(diào)Activity中的方法通過廣播载矿,這里又加了一種方案。
另外烹卒,Messenger一次發(fā)送一個(gè)請(qǐng)求闷盔,是串行,不存在并發(fā)旅急。因此服務(wù)端不需要考慮線程同步問題逢勾。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市藐吮,隨后出現(xiàn)的幾起案子溺拱,更是在濱河造成了極大的恐慌,老刑警劉巖谣辞,帶你破解...
    沈念sama閱讀 223,207評(píng)論 6 521
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盟迟,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡潦闲,警方通過查閱死者的電腦和手機(jī)攒菠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,455評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來歉闰,“玉大人辖众,你說我怎么就攤上這事卓起。” “怎么了凹炸?”我有些...
    開封第一講書人閱讀 170,031評(píng)論 0 366
  • 文/不壞的土叔 我叫張陵戏阅,是天一觀的道長。 經(jīng)常有香客問我啤它,道長奕筐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,334評(píng)論 1 300
  • 正文 為了忘掉前任变骡,我火速辦了婚禮离赫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘塌碌。我一直安慰自己渊胸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,322評(píng)論 6 398
  • 文/花漫 我一把揭開白布台妆。 她就那樣靜靜地躺著翎猛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪接剩。 梳的紋絲不亂的頭發(fā)上切厘,一...
    開封第一講書人閱讀 52,895評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音懊缺,去河邊找鬼迂卢。 笑死,一個(gè)胖子當(dāng)著我的面吹牛桐汤,可吹牛的內(nèi)容都是我干的而克。 我是一名探鬼主播,決...
    沈念sama閱讀 41,300評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼怔毛,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼员萍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拣度,我...
    開封第一講書人閱讀 40,264評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤碎绎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后抗果,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體筋帖,經(jīng)...
    沈念sama閱讀 46,784評(píng)論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,870評(píng)論 3 343
  • 正文 我和宋清朗相戀三年冤馏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了日麸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,989評(píng)論 1 354
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖代箭,靈堂內(nèi)的尸體忽然破棺而出墩划,到底是詐尸還是另有隱情,我是刑警寧澤嗡综,帶...
    沈念sama閱讀 36,649評(píng)論 5 351
  • 正文 年R本政府宣布乙帮,位于F島的核電站,受9級(jí)特大地震影響极景,放射性物質(zhì)發(fā)生泄漏察净。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,331評(píng)論 3 336
  • 文/蒙蒙 一盼樟、第九天 我趴在偏房一處隱蔽的房頂上張望氢卡。 院中可真熱鬧,春花似錦恤批、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,814評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至棋返,卻和暖如春延都,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背睛竣。 一陣腳步聲響...
    開封第一講書人閱讀 33,940評(píng)論 1 275
  • 我被黑心中介騙來泰國打工晰房, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人射沟。 一個(gè)月前我還...
    沈念sama閱讀 49,452評(píng)論 3 379
  • 正文 我出身青樓殊者,卻偏偏與公主長得像,于是被迫代替她去往敵國和親验夯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子猖吴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,995評(píng)論 2 361

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