Android上最簡單的IPC方案——Messenger

每個(gè)系統(tǒng)都會(huì)有相應(yīng)的 IPC 機(jī)制以方便開發(fā)者來進(jìn)行進(jìn)程間通訊,那么首先我們來梳理一下 Android 中的 IPC 機(jī)制有哪些:

  1. 組件間使用 Intent 傳遞數(shù)據(jù);
  2. 文件共享;
  3. Messenger;
  4. AIDL;
  5. ContentProvider;
  6. Socket;

這6種方式各有各的優(yōu)缺點(diǎn)和適用場(chǎng)景,在開發(fā)過程中最合適當(dāng)前需求的才是最好的。至于它們各自適用場(chǎng)景此處就不詳述了。今天主要來講一講這幾種機(jī)制中,功能強(qiáng)大但是使用起來卻非常簡單的 Messenger。

Messenger

Messenger 即信使的意思, 看起來它就與 Message 對(duì)象有關(guān),因?yàn)檫@個(gè)對(duì)象就是用來在不同進(jìn)程中傳遞 Message 對(duì)象的。

Messenger 是一種輕量級(jí)的 IPC 方案,它的底層實(shí)現(xiàn)是 AIDL。 因?yàn)樗鼘?duì) AIDL 做了封裝,所以使用起來非常簡單,就類似于我們綁定一個(gè) Service 一樣。同時(shí),由于它一次處理一個(gè)請(qǐng)求,所以在服務(wù)端我們不用考慮線程同步的問題,因?yàn)樵诜?wù)端中不存在并發(fā)執(zhí)行的情況。

下面我們就一步一步來實(shí)現(xiàn)一個(gè) Messenger 的例子,先從客戶端發(fā)送消息到服務(wù)端開始,然后再逐步完成其雙向通訊的功能。

Messenger 實(shí)現(xiàn)

要實(shí)現(xiàn)一個(gè) Messenger 的雙向通信的例子,那么肯定就需要實(shí)現(xiàn)服務(wù)端和客戶端這兩個(gè)部分。 我們先把實(shí)現(xiàn) Messenger 的幾個(gè)步驟列出來,再來代碼演示:

  • 服務(wù)端進(jìn)程

    1. 創(chuàng)建一個(gè) Service 來處理客戶端的連接請(qǐng)求;
    2. 創(chuàng)建一個(gè) Handler 并通過它來創(chuàng)建一個(gè) Messenger 對(duì)象;
    3. 在 Service 的 onBind 函數(shù)中返回這個(gè) Messenger 對(duì)象底層的 Binder ;
  • 客戶端進(jìn)程

    1. 綁定服務(wù)端的Service;
    2. 綁定成功后用服務(wù)端返回的 IBinder 對(duì)象創(chuàng)建一個(gè) Messenger;
    3. 通過這個(gè) Messenger 向服務(wù)端發(fā)送消息,消息類型為 Message 對(duì)象;
    4. 創(chuàng)建一個(gè) Handler 并創(chuàng)建一個(gè)新的 Messenger 對(duì)象;
    5. 將這個(gè)新的 Messenger 對(duì)象通過 Message 的 replyTo 參數(shù)傳遞給服務(wù)端,服務(wù)端就可以通過這個(gè) replyTo 參數(shù)回應(yīng)客戶端了;

客戶端發(fā)送信息到服務(wù)端

首先是服務(wù)端,我們需要實(shí)現(xiàn)一個(gè)典型的 Service 。在這個(gè) Service 中,創(chuàng)建一個(gè) MessengerHandler 對(duì)象用來接收客戶端的消息,并創(chuàng)建了一個(gè)與該Handler 相關(guān)聯(lián)的 Messenger,在 onBind 方法中返回它里面的 Binder 對(duì)象 :

public class MessengerService extends Service {

    private static class MessengerHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 10086:
                    Log.i("swifter", "服務(wù)端收到消息:"+msg.getData().getString("msg"));
                    break;
            }
        }
    }

    //此Messenger將客戶端發(fā)送的消息傳遞給 MessengerHandler
    private Messenger messenger = new Messenger(new MessengerHandler());

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

為了能夠讓該 Service 能夠在獨(dú)立的線程中,我們制定其 process :

<service android:name=".MessengerService"
         android:process=":remote" />

然后看看客戶端的實(shí)現(xiàn),基本就是一個(gè) Activity 綁定 Service 的標(biāo)準(zhǔn)寫法:

public class MainActivity extends Activity {

    private Messenger messenger;

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            messenger = new Messenger(service);
            //創(chuàng)建完成Messenger后就可以通過Messenger 來發(fā)送 Message 了
            Message message = Message.obtain();
            message.what = 10086;
            Bundle bundle = new Bundle();
            bundle.putString("msg", "this is message from client.");
            message.setData(bundle);

            try {    //通過信使發(fā)送信息
                messenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

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

        //綁定服務(wù)
        Intent intent = new Intent(this, MessengerService.class);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

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

運(yùn)行能看到log輸出:

I/swifter: 服務(wù)端收到消息:this is message from client.

在 Messenger 中進(jìn)行數(shù)據(jù)傳遞必須將數(shù)據(jù)放入 Message 中,而 Messenger 和 Message 都實(shí)現(xiàn)了 Parcelable 接口,因此可以跨進(jìn)程傳輸。簡單來說, Message 中所支持的數(shù)據(jù)類型就是 Messenger 所支持的傳輸類型。但是作為規(guī)范,還是使用 Bundle 來進(jìn)行要傳輸?shù)臄?shù)據(jù)的封裝是最好的。

服務(wù)端回應(yīng)客戶端

上面的例子演示了如何在服務(wù)端接受到客戶端發(fā)送的消息,為了進(jìn)行雙向通訊,下面就演示服務(wù)端如何回應(yīng)客戶端。

首先是服務(wù)端,需要更改的地方不多,只是在收到消息之后回復(fù)一條消息:

private static class MessengerHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 10086:
                Log.i("swifter", "服務(wù)端收到消息:"+msg.getData().getString("msg"));

                Messenger replyMessenger = msg.replyTo;
                Message replyMessage = Message.obtain();
                Bundle bundle = new Bundle();
                bundle.putString("reply", "服務(wù)端已經(jīng)收到消息");
                replyMessage.what = 10010;
                replyMessage.setData(bundle);
                try {
                    replyMessenger.send(replyMessage);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
        }
    }
}

在客戶端上,為了接受服務(wù)端的信息,客戶端也需要實(shí)現(xiàn)一個(gè) Messenger :

private static class MessengerHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 10010:
                Log.i("swifter", "客戶端收到消息:"+msg.getData().getString("reply"));
                break;
        }
    }
}

private Messenger replyMessenger = new Messenger(new MessengerHandler());

除此之外,我們還需要將這個(gè)replyMessenger設(shè)置到要發(fā)送的 Message 的 replyTo 參數(shù)中去,這樣服務(wù)器才能拿到這個(gè)參數(shù)并回應(yīng)信息。

message.replyTo = replyMessenger;

運(yùn)行程序能看到log如下:

I/swifter: 服務(wù)端收到消息:this is message from client.
I/swifter: 客戶端收到消息:服務(wù)端已經(jīng)收到消息

至此,使用 Messenger 進(jìn)行客戶端與服務(wù)端之間的雙向通信還是蠻容易的,相比 AIDL, 這個(gè)方案相當(dāng)?shù)谋憬荨R驗(yàn)槭褂玫氖谴蟹绞教幚硇畔?,所?Messenger 比較適用于第并發(fā)的一對(duì)多的通信。不同的場(chǎng)景下還是需要找到最合適的方案。還是那句話,每個(gè)方案都是針對(duì)不同的業(yè)務(wù)場(chǎng)景而設(shè)計(jì)的,總之,找到合適的就是最好的。

69fa3f23-c8c6-41b4-a00f-e29bdc6106b1.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容