1膘流、Messenger 簡介
說到Android進程間通信樱衷,大家肯定能想到的是編寫aidl文件膀曾,然后通過aapt生成的類方便的完成服務端,以及客戶端代碼的編寫墙基。如果你對這個過程不熟悉软族,可以查看Android aidl Binder框架淺析;
當然今天要說的通信方式肯定不是通過編寫aidl文件的方式残制,那么有請今天的主角:Messenger立砸。ok,這是什么樣的一個類呢初茶?我們看下注釋
This allows for the implementation of message-based communication across processes
允許實現基于消息的進程間通信方式颗祝。
平時一說進程間通訊,大家都會想到AIDL纺蛆,其實messenger和AIDL作用一樣吐葵,都可以進行進程間通訊。它是基于消息的進程間通信桥氏,就像子線程和UI線程發(fā)送消息那樣温峭,是不是很簡單,還不用去寫AIDL文件字支,是不是有點小爽凤藏。哈哈。
此外堕伪,還支持記錄客戶端對象的Messenger揖庄,然后可以實現一對多的通信;甚至作為一個轉接處欠雌,任意兩個進程都能通過服務端進行通信蹄梢。
與 AIDL 比較:
當您需要執(zhí)行 IPC 時,為您的接口使用 Messenger 要比使用 AIDL 實現更加簡單富俄,因為 Messenger 會將所有服務調用排入隊列禁炒,而純粹的 AIDL 接口會同時向服務發(fā)送多個請求,服務隨后必須應對多線程處理霍比。
對于大多數應用幕袱,服務不需要執(zhí)行多線程處理,因此使用 Messenger 可讓服務一次處理一個調用悠瞬。如果您的服務必須執(zhí)行多線程處理们豌,則應使用 AIDL 來定義接口涯捻。
2、通信實例
1)Service端
代碼
package com.ryg.chapter_2.messenger;
import android.app.Service;
import android.content.Intent;
import android.os.*;
import android.util.Log;
import com.ryg.chapter_2.utils.MyConstants;
/**
* FileName:
* Author: nanzong
* Date: 2019-06-20 17:23
* Description:
* History:
*/
public class MessengerService extends Service {
private static final String TAG = "MessengerActivity";
private static class MessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyConstants.MSG_FROM_CLIENT:
Log.d(TAG, "receive msg from Client:" + msg.getData().getString("mymsg"));
Messenger msgfromClient = msg.replyTo;
Message relpyMessage = Message.obtain(null, MyConstants.MSG_FROM_SERVICE);
Bundle bundle = new Bundle();
bundle.putString("reply", " 嗯 望迎, 你的消息我已經收到障癌,稍后會回復你!");
relpyMessage.setData(bundle);
try {
msgfromClient.send(relpyMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}
private final Messenger mMessenger = new Messenger(new MessengerHandler());
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
服務端就是一個Service,只需要去聲明一個Messernger (Handler handler)對象擂煞,然后onBind方法中返回一個mMessenger.getBinder();
然后等客戶端將消息發(fā)送到Handler中的handleMessage混弥,根據msg.what去判斷什么操作,最終將結果通過msgfromClient.replyTo.send(relpyMessage);返回
注冊文件
<service
android:name=".messenger.MessengerService"
android:process=":remote" >
<intent-filter>
<action android:name="com.ryg.MessengerService.launch" />
</intent-filter>
</service>
別忘了注冊service
2)客戶端
Activity
package com.ryg.chapter_2.messenger;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.*;
import android.util.Log;
import com.ryg.chapter_2.R;
import com.ryg.chapter_2.utils.MyConstants;
public class MessengerActivity extends Activity {
private static final String TAG = "MessengerActivity";
private Messenger mServerMessenger;
@SuppressLint("HandlerLeak")
private Messenger mClientMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyConstants.MSG_FROM_SERVICE:
Log.d(TAG, "receive msg from Service:" + msg.getData().getString("reply"));
break;
default:
super.handleMessage(msg);
}
}
});
private ServiceConnection mConnection = new ServiceConnection() {
//Activity 與 Service連接成功使回調該方法
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
mServerMessenger = new Messenger(service);
Log.d(TAG, "bind service");
Message msg = Message.obtain(null, MyConstants.MSG_FROM_CLIENT);
Bundle data = new Bundle();
data.putString("mymsg", "hello, this is client.");
msg.setData(data);
msg.replyTo = mClientMessenger; //指定回信人是客戶端定義的
try {
mServerMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
//Activity 與 Service 斷開連接 回調該方法
@Override
public void onServiceDisconnected(ComponentName name) {
mServerMessenger = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger);
//綁定服務
Intent intent = new Intent(this, MessengerService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
}
}
首先bindService,然后再onServiceConnected中拿到回調的service( Binder)對象对省,通過 mServerMessenger = new Messenger(service);然后就可以使用mServerMessenger.send(msg);發(fā)送給服務端了
mServerMessenger = new Messenger(service);
Log.d(TAG, "bind service");
Message msg = Message.obtain(null, MyConstants.MSG_FROM_CLIENT);
Bundle data = new Bundle();
data.putString("mymsg", "hello, this is client.");
msg.setData(data);
msg.replyTo = mClientMessenger; //指定回信人是客戶端定義的
try {
往服務端發(fā)送消息
mServerMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
那么服務端會收到消息蝗拿,處理完成會將結果返回,傳到client的mMessenger中的Handler的handleMessage方法中給對應地方進行處理
3) 運行結果
2019-06-28 08:56:57.480 21990-21990/com.ryg.chapter_2 D/MessengerActivity: bind service
2019-06-28 08:56:59.482 22039-22039/com.ryg.chapter_2:remote D/MessengerActivity: receive msg from Client:hello, this is client.
2019-06-28 08:56:59.482 21990-21990/com.ryg.chapter_2 D/MessengerActivity: receive msg from Service: 嗯 蒿涎, 你的消息我已經收到哀托,稍后會回復你!
通過代碼可以看到服務端往客戶端傳遞數據是通過msg.replyTo這個對象的劳秋,那么服務端完全可以做到仓手,使用一個List甚至Map去存儲所有綁定客戶端的msg.replyTo對象,然后想給誰發(fā)消息都可以玻淑。
3嗽冒、源碼分析
Messenger 有兩個構造函數
- 以Handler 為參數
- 以IBinder 為參數
//服務端構建對象
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
//客戶端構建對象
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target); //和前面的 AIDL 很相似吧
}
1)客戶端向服務端通信
服務端
服務端的onBind是這么寫的:
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
那么點進去:
/**
* Retrieve the IBinder that this Messenger is using to communicate with
* its associated Handler.
*
* @return Returns the IBinder backing this Messenger.
*/
public IBinder getBinder() {
return mTarget.asBinder();
}
可以看到返回的是mTarget.asBinder();
我們前邊構建Messenger對象的代碼 new Messenger(new Handler());
mTarget就是這么來的
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
Handler返回
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
mTarget是一個MessengerImpl對象补履,那么asBinder實際上是返回this添坊,也就是MessengerImpl對象;
這是一個內部類箫锤,繼承IMessenger.Stub贬蛙,然后實現了一個send方法,該方法就是將接收到的消息通過Handler.this.sendMessage(msg);發(fā)送到handleMessage方法谚攒。
看到這阳准,大家有沒有想到什么,難道不覺得extends IMessenger.Stub這種寫法異常的熟悉么馏臭?
我們傳統(tǒng)寫aidl文件野蝇,aapt給我們生成什么,生成IXXX.Stub類括儒,然后我們服務端繼承IXXX.Stub實現接口中的方法浪耘。
這里依賴了一個aidl生成的類
/Users/nanzong/Library/Android/sdk/sources/android-28/android/os/IMessenger.aidl
package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger {
void send(in Message msg);
}
Messenger就是依賴了該aidl文件生成的類,繼承了該類的IMessenger.Stub類塑崖,實現了send方法,send方法中參數會通過客戶端傳遞過來痛倚,最終發(fā)送給Handler進行處理规婆。
客戶端
客戶端首先通過onServiceConnected拿到sevice(Ibinder)對象,這里沒什么特殊的,我們平時的寫法也是這樣的抒蚜,只不過我們平時會這么寫:
IMessenger.Stub.asInterface(service)拿到接口對象進行調用掘鄙;
我們代碼中是
mService = new Messenger(service);
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
和我們平時aidl寫法沒有任何區(qū)別,通過編寫aidl文件嗡髓,服務端onBind利用Stub編寫接口實現返回操漠;客戶端利用回調得到IBinder對象,使用IMessager.Stub.asInterface(target)拿到接口實例進行調用饿这;
2)服務端與客戶端通信
那么浊伙,客戶端與服務端通信的確沒什么特殊的地方,我們完全也可以編寫個類似的aidl文件實現长捧;那么服務端是如何與客戶端通信的呢嚣鄙?
還記得,客戶端send方法發(fā)送的是一個Message串结,這個Message.replyTo指向的是一個mMessenger哑子,我們在Activity中初始化的。
那么將消息發(fā)送到服務端肌割,肯定是通過序列化與反序列化拿到Message對象卧蜓,我們看下Message的反序列化的代碼:
# Message
private void readFromParcel(Parcel source) {
what = source.readInt();
arg1 = source.readInt();
arg2 = source.readInt();
if (source.readInt() != 0) {
obj = source.readParcelable(getClass().getClassLoader());
}
when = source.readLong();
data = source.readBundle();
replyTo = Messenger.readMessengerOrNullFromParcel(source);
sendingUid = source.readInt();
}
主要看replyTo,調用的Messenger.readMessengerOrNullFromParcel
public static Messenger readMessengerOrNullFromParcel(Parcel in) {
IBinder b = in.readStrongBinder();
return b != null ? new Messenger(b) : null;
}
public static void writeMessengerOrNullToParcel(Messenger messenger, Parcel out) {
out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder() : null);
}
通過上面的writeMessengerOrNullToParcel可以看到把敞,它將客戶端的messenger.mTarget.asBinder()對象進行了恢復弥奸,客戶端的message.mTarget.asBinder()是什么?
客戶端也是通過Handler創(chuàng)建的Messenger先巴,于是asBinder返回的是:
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
public IBinder getBinder() {
return mTarget.asBinder();
}
那么asBinder其爵,實際上就是MessengerImpl extends IMessenger.Stub中的asBinder了。
#IMessenger.Stub
@Override
public android.os.IBinder asBinder(){
return this;
}
那么其實返回的就是MessengerImpl對象自己伸蚯。到這里可以看到message.mTarget.asBinder()其實返回的是客戶端的MessengerImpl對象摩渺。
msgfromClient.replyTo.send(msgToClient);
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
這個mTarget實際上就是對客戶端的MessengerImpl對象的封裝,那么send(message)(屏蔽了transact/onTransact的細節(jié))剂邮,這個message最終肯定傳到客戶端的handler的handleMessage方法中摇幻。
總結下:
客戶端與服務端通信,利用的aidl文件挥萌,沒什么特殊的
服務端與客戶端通信绰姻,主要是在傳輸的消息上做了處理,讓Messager.replyTo指向的客戶端的Messenger,而Messenger又持有客戶端的一個Binder對象(MessengerImpl)引瀑。服務端正是利用這個Binder對象做的與客戶端的通信狂芋。