Android中使用 Messenger 實現進程間通信小案例與分析說明

Messenger 是什麼

Messenger 可以翻譯爲信使,顧名思義,通過它可以實現在不同進程中傳遞 Message 對象,在 Message 中可以攜帶我們需要傳遞的數據,藉此就可以實現數據在不同進程間的通信。


Messenger 底層實現

Messenger 是一種輕量級的 IPC 方案,它的底層實現是 AIDL ,這塊同學們可以通過看 Messenger 這個類的源碼中的構造方法得知。


Messenger 使用說明

Messenger的使用會相對簡單,它對 AIDL 做了封裝,使得我們可以更便捷的進行進程間通信。
同時,由於它一次處理一個請求,因此服務端我們不用考慮線程同步的問題,這是因爲服務端此時不存在併發執行的情形。


案例實現

說明

案例只用到了一個應用,首先是一個 Activity,把Activity 裏的代碼當作客戶端的代碼,後面統稱客戶端;服務端我們用一個 Service 組件(後面統稱服務端)來實現,然後通過客戶端和 Service 綁定來啓動服務端,進而模擬實現客戶端和服務端的通信。

同學們這時候有疑問了?

你這不是在同一個進程嗎?不急往下看。

這裏我們創建好 Service 後,會另外在清單配置文件中給 Service 組件添加一個 process 屬性,用來使 Service 組件運行在另一個進程。這樣就可以在一個應用中模擬兩個進程的運行了,也方便demo的實現。

至於組件的 process 屬性,同學們自行查閱資料學習,這裏不細說了。

清單配置文件如下圖示:

在這裏插入圖片描述


新建一個項目

新建操作,我就不給出了,同學們自己完成。


創建 Service

項目新建完成後,帶有一個 Activity ,我們就當作客戶端用,然後再創建一個 Service,命名爲 MessengerService.java ,如下圖示:

在這裏插入圖片描述
在這裏插入圖片描述

這裏只用到了 3 個類,其中 MyConstant.java 的代碼如下圖示:

在這裏插入圖片描述
別忘記在清單配置文件中給 MessengerService 這個服務配置 process 屬性,如下圖示:

在這裏插入圖片描述

到這裏我們就擁有了客戶端和服務端了。


Service 代碼說明

首先給出代碼,如下:

package com.example.messengerdemo.service;

import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

import com.example.messengerdemo.constant.MyConstant;

public class MessengerService extends Service {

    private static final String TAG = "MessengerService";

    public MessengerService() {
    }

    private static class MessengerHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MyConstant.MSG_FROM_CLIENT:

                    // 接收客戶端發來的消息並打印
                    Log.e(TAG, "receive msg from client:" + msg.getData().getString(MyConstant.MSG));

                    // 獲取客戶端的 Messenger 對象,用來回復客戶端消息
                    Messenger clientMessenger = msg.replyTo;
                    Message replyMessage = Message.obtain(null, MyConstant.MSG_FROM_SERVER);
                    Bundle bundle = new Bundle();
                    bundle.putString(MyConstant.REPLY, "消息已經收到,稍後回覆你。");
                    replyMessage.setData(bundle);
                    try {
                        clientMessenger.send(replyMessage);// 回覆客戶端:服務端我已經接收消息
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }

                    break;
            }
        }
    }

    // 創建 Messenger 對象,作用是將客戶端的發送的消息傳遞給 MessengerHandler 處理
    private final Messenger messenger = new Messenger(new MessengerHandler());

    @Override
    public IBinder onBind(Intent intent) {
        // 服務端返回 Messenger 對象底層的 binder
        return messenger.getBinder();
    }
}

首先,我們創建一個服務端的 Handler,這裏命名爲 MessengerHandler 繼承 Handler,然後重寫 handleMessage() 方法來處理客戶端發來的消息,如下圖示:

在這裏插入圖片描述

那麼消息怎麼傳遞給 MessengerHandler 呢,我們就要用到 Messenger 對象了,所以需要創建一個 Messenger 對象,如下圖示:

在這裏插入圖片描述

然後你在客戶端需要獲取到服務端的 Messenger 對象,這樣才能給服務端發消息,所以還需要在 onBind() 方法中返回服務端 Messenger 對象底層的 binder,如下圖示:

在這裏插入圖片描述

所以我們到這裏就可以知道,創建一個 Messenger 對象,他的構造方法裏的參數既可以是 Handler 類型參數,也可以是 IBinder 類型的參數,這裏通過看類的源碼的構造方法可以看出,如下圖示:

在這裏插入圖片描述


客戶端代碼說明

首先給出 activity 中的代碼,如下:

package com.example.messengerdemo.activity;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;

import com.example.messengerdemo.R;
import com.example.messengerdemo.constant.MyConstant;
import com.example.messengerdemo.service.MessengerService;

public class MainActivity extends AppCompatActivity{

    // 服務端通過獲取客戶端的 Messenger 對象 回覆消息給客戶端 所以客戶端也需要聲明這麼一個 Messenger 對象
    private Messenger getReplyMessenger = new Messenger(new MessengerHandle());
    private static class MessengerHandle extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MyConstant.MSG_FROM_SERVER:

                    Log.e("TAG", "receive msg from server:" +
                            msg.getData().getString(MyConstant.REPLY));

                    break;
            }
        }
    }

    private Messenger messenger = null;// 聲明 Messenger 對象,初始化獲取服務端的Messenger對象用

    // 創建 ServiceConnection 對象
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            messenger = new Messenger(iBinder);// 通過服務端返回的 binder 創建 Messenger 對象

            // 創建Message對象並設置攜帶的數據
            Message message = Message.obtain(null, MyConstant.MSG_FROM_CLIENT);
            Bundle bundle = new Bundle();
            bundle.putString(MyConstant.MSG, "imxiaoqi, enjoy coding.");
            message.setData(bundle);

            message.replyTo = getReplyMessenger;// 保證服務端處理消息的時候,能獲取到客戶端的Messenger對象
            try {
                messenger.send(message);// 通過服務端的Messenger對象發送消息給服務端
            } catch (RemoteException e) {
                e.printStackTrace();
            }

        }

        // 在正常情況下該方法是不被調用的,它的調用時機是當Service服務被異外銷燬時,權例如內存的資源不足時
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.e("TAG", "MainActivity onServiceDisconnected callback");
        }
    };

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

        // 綁定服務,開啓了新的服務進程(後面統一稱服務端)
        Intent intent = new Intent(MainActivity.this, MessengerService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 活動銷燬,記得解綁服務
        unbindService(connection);
    }

}

在onCreate() 方法中,我們綁定服務開啓服務端進程,如下圖示:

在這裏插入圖片描述

onDestory() 方法就是正常的解綁服務的操作,沒什麼好說的;

這裏同學們應該有注意到,綁定服務的代碼中有一個 connection 參數,這個參數其實一個 ServiceConnection 對象,所以我們還需要創建一個 ServiceConnection 對象,這個對象的作用是用來獲取服務端的 Messenger 對象並給服務端發送消息,這些操作是在 onServiceConnected() 方法中實現,正常通過綁定方式啓動服務並建立連接後,會回調該方法,如下圖示:

在這裏插入圖片描述

上圖中創建 Message 對象並設置攜帶的數據以及通過服務端的 Messenger 對象發送消息給服務端大家都比較好理解。

但是有一行代碼可能同學們會存在疑惑,就是
message.replyTo = getReplyMessenger;// 保證服務端處理消息的時候,能獲取到客戶端的Messenger對象
。其實這行代碼的作用是:爲了在發給服務端的消息中攜帶客戶端的 Messenger 對象,這樣服務端就可以通過 message(客戶端發來的) 獲取客戶端的 Messenger 對象,也就能使用這個對象回覆消息給客戶端說我已經接收到你的消息了。

所以,如果服務端需要回復消息給客戶端,那麼我們的客戶端肯定也是需要有一個 Messenger 對象和 一個 Handler 對象的,只有存在這兩個對象纔可以接收到服務端的消息並作處理,如下圖示:

在這裏插入圖片描述

服務端獲取客戶端的 Messenger 對象代碼,如下圖示:

在這裏插入圖片描述


小結

到這裏代碼就全部完成,我們來梳理一下上面都做了什麼操作,可以實現什麼功能?

我們在一個應用中模擬了客戶端和服務端,並運行在不同進程;然後客戶端可以發消息給服務端,服務端接收到消息並處理消息,log打印客戶端消息;同時服務端收到消息後,再回應客戶端說我已經接收到你發給我的消息了,這時候我們在客戶端接收到消息並處理後,也用log打印服務端回覆的消息。


驗證結果

我這裏連接到了自己的手機,運行應用測試,我們來看一下。

  • usb連接手機,點擊按鈕運行應用:
    在這裏插入圖片描述

  • 運行成功後打開 logcat 窗口查看日誌:

在這裏插入圖片描述
上圖說明服務端已經接收到客戶端的消息並做了打印

  • 兩個組件運行在兩個不同進程,如下:

在這裏插入圖片描述
com.example.messengerdemo這個對應 activity 的進程,com.example.messengerdemo:remote這個對應 service 組件的進程

  • 切換到 activity 進程打印窗口查看,如下:

在這裏插入圖片描述
上面說明客戶端已經接收到了服務端回覆的消息

  • 到這裏就完成了使用 Messenger 實現進程間通信的小案例,希望對同學們有所幫助。

Messenger 工作原理

Client
Client-Message
Service
Service-Handler
Client-Handler
Service-Message
Messenger
replyTo-Messenger

總結

這裏再次強調,之所以選擇在同一個應用內進行進程間通信,是因爲操作起來方便,方便,方便。但是效果和在兩個應用間進行進程間通信時一樣的。

還有一點大家需要知道:同一個應用的不同組件,如果它們運行在不同進程中,那麼和它們分別屬於兩個應用沒有本質區別。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章