文章目錄
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 工作原理
總結
這裏再次強調,之所以選擇在同一個應用內進行進程間通信,是因爲操作起來方便,方便,方便。但是效果和在兩個應用間進行進程間通信時一樣的。
還有一點大家需要知道:同一個應用的不同組件,如果它們運行在不同進程中,那麼和它們分別屬於兩個應用沒有本質區別。