今天我們來聊一聊Android中另外一種IPC機(jī)制-Messenger路星,可以理解成信使并蝗,通過它可以在不同的進(jìn)程中傳遞Message對(duì)象卧檐,其實(shí)它的底層實(shí)現(xiàn)還是AIDL克懊,為什么這么說忱辅?先賣個(gè)關(guān)子,繼續(xù)往后看就知道了谭溉。我們先看下Messenger怎么使用墙懂。還是通過一個(gè)栗子來說明,客戶端向服務(wù)端發(fā)起請(qǐng)求扮念,服務(wù)端返回一個(gè)百度的url损搬,客戶端再進(jìn)行加載,就是這么簡(jiǎn)單柜与。
當(dāng)然在這之前有點(diǎn)AIDL的知識(shí)看起來會(huì)比較輕松巧勤,可以參考我前面的AIDL的博客:http://www.reibang.com/p/4ebd4783d3d9
Messenger基本使用
當(dāng)然還是分成服務(wù)端進(jìn)程和服務(wù)端進(jìn)程
服務(wù)端進(jìn)程
首先創(chuàng)建一個(gè)Service來處理客戶端的連接請(qǐng)求,創(chuàng)建一個(gè)Messenger弄匕,在onBind中返回這個(gè)Messenger對(duì)象底層的Binder給客戶端即可颅悉。
通過Handler來創(chuàng)建Messenger,在收到客戶端發(fā)過來的請(qǐng)求時(shí)會(huì)回送一個(gè)msg:clientMessenger.send(response);
private Messenger messenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
try {
Thread.sleep(5 * 1000); //模擬耗時(shí)
} catch (Exception e) {
e.printStackTrace();
}
Message response = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString("body", REMOTE_URL);
response.setData(bundle);
Messenger clientMessenger = msg.replyTo;
try {
clientMessenger.send(response);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
客戶端需要在清單中進(jìn)行注冊(cè),在另外一個(gè)juexingzhe進(jìn)程
<service android:name=".MessengerService" android:process=":juexingzhe"/>
在客戶端綁定服務(wù)的時(shí)候返回這個(gè)Messenger對(duì)象迁匠。
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
客戶端進(jìn)程
客戶端首先發(fā)起綁定服務(wù)的請(qǐng)求剩瓶,在服務(wù)綁定成功后,通過服務(wù)端返回的IBinder對(duì)象就可以創(chuàng)建一個(gè)Messenger mSender城丧,通過它就可以向服務(wù)端發(fā)送信息了延曙。
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mSender = new Messenger(iBinder);
sendMessage();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
客戶端還需要?jiǎng)?chuàng)建一個(gè)Handler,通過Handler來創(chuàng)建一個(gè)Messenger亡哄,用來接收服務(wù)端發(fā)送的消息:
private Messenger mReceiver = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.i(TAG, "msg is received from service");
Bundle data = msg.getData();
if (null != data) {
mButton.setVisibility(View.GONE);
String body = data.getString("body");
mWebView.loadUrl(body);
}
}
});
Messenger源碼分析
使用還是比較簡(jiǎn)單的枝缔,基本和Handler的用法比較類似。我們下面來扒一扒源碼蚊惯。
1.構(gòu)造
我們?cè)谏厦娴睦又杏玫搅藘蓚€(gè)Messenger的構(gòu)造函數(shù):
一個(gè)是在服務(wù)綁定成功后mSender = new Messenger(iBinder);
另外一個(gè)是在創(chuàng)建的時(shí)候private Messenger mReceiver = new Messenger(new Handler())
我們先看下通過Binder的構(gòu)造函數(shù)愿卸,可以看見濃濃的AIDL的味道吧拐辽。在夸進(jìn)程通信的情況下,通過asInterface會(huì)將返回服務(wù)端Binder的代理Proxy擦酌。
/**
* Create a Messenger from a raw IBinder, which had previously been retrieved with {@link #getBinder}.
*
* @param target The IBinder this Messenger should communicate with.
*/
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
我們?cè)倏聪峦ㄟ^Handler的構(gòu)造函數(shù)俱诸,只有一行代碼,就是獲取mTarget對(duì)象赊舶。
/**
* Create a new Messenger pointing to the given Handler. Any Message
* objects sent through this Messenger will appear in the Handler as if
* {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had
* been called directly.
*
* @param target The Handler that will receive sent messages.
*/
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
上面兩個(gè)構(gòu)造函數(shù)無一例外都是獲得mTarget對(duì)象睁搭,它是一個(gè)IMessenger對(duì)象
private final IMessenger mTarget;
IMessenger就是Android系統(tǒng)幫我們定義在android.os包下的一個(gè)AIDL接口,編譯后會(huì)生成IMessenger.java文件。
package android.os;
import android.os.Message;
oneway interface IMessenger{
void send(in Message msg);
}
因此mTarget有兩種情況,一種是通過Handler或的IMessenger:
mTarget = Handler.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);
}
}
一種是通過IBinder轉(zhuǎn)化得到的IMessenger:
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
public static android.os.IMessenger asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin =obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof android.os.IMessenger))) {
return ((android.os.IMessenger) iin);
}
return new android.os.IMessenger.Stub.Proxy(obj);
}
2.發(fā)送消息
Messenger發(fā)送消息的源碼,都是通過mTarget進(jìn)行發(fā)送笼平。
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
發(fā)送消息要分成兩種情況:
給服務(wù)端發(fā)送消息
一種是客戶端給服務(wù)端發(fā)送消息(這種情況的Messenger是客戶端通過服務(wù)端返回的IBinder進(jìn)行構(gòu)造)园骆,
private void sendMessage() {
if (null != mSender) {
Message msg = Message.obtain();
msg.replyTo = mReceiver;
mSender.send(msg);
}
}
這種情況下會(huì)的調(diào)用流程會(huì)是這樣的(注意前方高能,可能會(huì)引起輕微不適):
Proxy.send()--->mRemote.transact(Stub.TRANSACTION_send, _data, null, android.os.IBinder.FLAG_ONEWAY)--->Stub.onTransact--->this.send(_arg0)(這里面的arg0就是msg)--->Handler中MessengerImpl.send()--->handler.sendMessage--->服務(wù)端handleMessage
上面這個(gè)過程會(huì)比較繞:
1.因?yàn)楹头?wù)端通信是跨進(jìn)程寓调,所以首先會(huì)在Proxy中序列化msg參數(shù)(包括bundle和Messenger)锌唾,然后會(huì)調(diào)用到服務(wù)端進(jìn)程的onTransact;
2.在服務(wù)端進(jìn)程中會(huì)調(diào)用this.send夺英,那這邊的this指的是哪個(gè)對(duì)象晌涕?還記得服務(wù)端Messenger是怎么創(chuàng)建的嗎?也是通過Handler創(chuàng)建的痛悯,因此this.send就會(huì)調(diào)用服務(wù)端Messenger的Handler中內(nèi)部類MessengerImpl中的send方法余黎;
3.MessengerImpl中的send方法會(huì)調(diào)用Handler的sendMessage方法
Handler.this.sendMessage(msg);
明顯這里的Handler就是服務(wù)端構(gòu)建Messenger我們傳進(jìn)去的handler,因此msg也就被handleMessage處理载萌。
給客戶端發(fā)送消息
這種情況下會(huì)拿到客戶端發(fā)送過來的Messenger惧财,那么為什么服務(wù)端可以直接拿到Messenger就給客戶端發(fā)送消息,不是應(yīng)該先拿到一個(gè)客戶端的Binder扭仁,然后再轉(zhuǎn)化balabalabalabala嗎垮衷?
Messenger clientMessenger = msg.replyTo;
clientMessenger.send(response);
其實(shí)Android也是這樣做的,我們?nèi)ヒ惶骄烤梗ㄗⅲ合路皆创a是我經(jīng)過刪減的):
在客戶端send消息給服務(wù)端時(shí)會(huì)乖坠,在Proxy的send方法中會(huì)將msg和clientMessenger一起會(huì)調(diào)用Message msg.writeToParcel(_data, 0)寫到data中搀突;
public void send(android.os.Message msg) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
_data.writeInterfaceToken(DESCRIPTOR);
if ((msg != null)) {
_data.writeInt(1);
msg.writeToParcel(_data, 0);
}
}
在Message的writeToParcel方法中會(huì)調(diào)用writeMessengerOrNullToParcel,然后在方法中會(huì)在data中writeStrongBinder瓤帚,會(huì)將clientMessenger的Binder存儲(chǔ)起來描姚,是不是恍然大悟?戈次?轩勘?
Messenger.writeMessengerOrNullToParcel(replyTo, dest);
dest.writeInt(sendingUid);
public static void writeMessengerOrNullToParcel(Messenger messenger, Parcel out) {
out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder(): null);
}
接下來就順利成章了,服務(wù)端會(huì)在onTransact中調(diào)用CREATOR怯邪;
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_send: {
data.enforceInterface(DESCRIPTOR);
android.os.Message _arg0;
if ((0 != data.readInt())) {
_arg0 = android.os.Message.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.send(_arg0);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
public static final Parcelable.Creator<Message> CREATOR
= new Parcelable.Creator<Message>() {
public Message createFromParcel(Parcel source) {
Message msg = Message.obtain();
msg.readFromParcel(source);
return msg;
}
public Message[] newArray(int size) {
return new Message[size];
}
};
然后會(huì)調(diào)用Message的readFromParcel,接著就是readMessengerOrNullFromParcel绊寻,在該方法中會(huì)得到clientMessenger
private void readFromParcel(Parcel source) {
replyTo = Messenger.readMessengerOrNullFromParcel(source);
sendingUid = source.readInt();
}
public static Messenger readMessengerOrNullFromParcel(Parcel in) {
IBinder b = in.readStrongBinder();
return b != null ? new Messenger(b) : null;
}
可以看到服務(wù)端發(fā)送消息也是通過Binder,之后過程就與客戶端發(fā)送消息服務(wù)端一樣了,就不做分析了澄步。
其他
因?yàn)镸essenger在進(jìn)程內(nèi)是通過Handler進(jìn)行消息發(fā)送和處理的冰蘑,所以只能串行發(fā)送消息和處理消息;
Messenger跨進(jìn)程調(diào)用方法是非阻塞的村缸,這個(gè)在我們栗子中可以體現(xiàn)祠肥,客戶端發(fā)送消息后會(huì)馬上打印后面的log,一段時(shí)間后服務(wù)端才返回消息梯皿。還記得IMessenger.aidl這個(gè)文件仇箱?有oneway這個(gè)關(guān)鍵字,這個(gè)就是非阻塞的原因东羹,具體可以看后面參考鏈接中的博客剂桥。
private void sendMessage() {
mSender.send(msg);
Log.i(TAG, "msg is right now send");
}
private Messenger mReceiver = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.i(TAG, "msg is received from service");
}
});
Messenger其實(shí)就是Android幫我們封裝好的AIDL,用法和Handler類似属提,比較方便权逗,文中的代碼可以在Github中看到:https://github.com/juexingzhe/MessengerSample
好了,我們今天的Messenger之旅就到此結(jié)束了冤议。謝謝斟薇!
參考鏈接:
http://www.reibang.com/p/c6a73b9a14ce
http://www.reibang.com/p/4ebd4783d3d9
歡迎關(guān)注公眾號(hào):JueCode