您的位置:首页 > 移动开发 > Android开发

Android 进阶10:进程通信之 Messenger 使用与解析

2017-06-01 22:57 776 查看
读完本文你将了解:

Messenger 简介

Messenger 的使用
服务端

客户端

运行效果

使用小结

总结

代码地址

Thanks

前面我们介绍了 AIDL 的使用与原理,这篇文章来介绍下 Android 中另一种 IPC 方式:Messenger。

Messenger 简介

Messenger “信使”,顾名思义,它的作用就是传递信息。

Messenger 有两个构造函数:

以 Handler 为参数

以 Binder 为参数

private final IMessenger mTarget;
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);    //和前面的 AIDL 很相似吧
}


看下
Handler.getIMessenger()
源码:

final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}


这个
IMessanger
应该也是个 AIDL 生成的类吧,看下源码,果然是:

public interface IMessenger extends android.os.IInterface {
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements
android.os.IMessenger {
private static final java.lang.String DESCRIPTOR = "android.os.IMessenger";

public Stub() {
this.attachInterface(this, DESCRIPTOR);
}

public static android.os.IMessenger asInterface(...}

public android.os.IBinder asBinder() {
return this;
}

@Override
public boolean onTransact(int code, android.os.Parcel data,
android.os.Parcel reply, int flags)
throws android.os.RemoteException {...}

private static class Proxy implements android.os.IMessenger {...}

public void send(android.os.Message msg)
throws android.os.RemoteException;
}


IMessenger
是 AIDL 生成的跨进程接口,里面定义了一个发送消息的方法:

public void send(android.os.Message msg)
throws android.os.RemoteException;


Handler
MessengerImpl
实现了这个方法,就是使用 Handler 将消息发出去:

private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}


这就解释了为什么我们的消息来得时候会出现在
Handler.handlerMessage()


接着再看下 Messenger 另一个重要的方法,
send()


public void send(Message message) throws RemoteException {
mTarget.send(message);
}


Messenger
中持有一个
IMessenger
的引用,在构造函数中可以通过
Handler
或者
Binder
的形式获得最终的
IMessenger
实现,然后调用它的
send()
方法。

Messenger
其实就是 AIDL 的简化版,它把接口都封装好,我们只需在一个进程创建一个
Handler
传递给 Messenger,Messenger 帮我们把消息跨进程传递到另一个进程,我们在另一个进程的 Handler 在处理消息就可以了。

Messenger 的使用

Messenger 的使用需要结合
Handler
,
Message
,
Bundle


下面我们将写一个客户端跨进程发送消息到服务端的例子,服务端在收到消息后会回复,由于在 Messenger 中一个对象对应一个 Handler,所以我们需要在客户端、服务端分别创建一个 Messenger:



服务端在收到消息后会使用
Message.replyTo
对应的信使回复消息。

服务端

服务端只需要创建一个 Messenger 对象,然后给它传递一个 Handler,在 Handler 中处理消息:

public class MessengerService extends BaseService {

private final String TAG = this.getClass().getSimpleName();

Messenger mMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(final Message msg) {
if (msg != null && msg.arg1 == ConfigHelper.MSG_ID_CLIENT) {
if (msg.getData() == null) {
return;
}
String content = (String) msg.getData().get(ConfigHelper.MSG_CONTENT);  //接收客户端的消息
LogUtils.d(TAG, "Message from client: " + content);

//回复消息给客户端
Message replyMsg = Message.obtain();
replyMsg.arg1 = ConfigHelper.MSG_ID_SERVER;
Bundle bundle = new Bundle();
bundle.putString(ConfigHelper.MSG_CONTENT, "听到你的消息了,请说点正经的");
replyMsg.setData(bundle);

try {
msg.replyTo.send(replyMsg);     //回信
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});

@Nullable
@Override
public IBinder onBind(final Intent intent) {
return mMessenger.getBinder();
}
}


客户端

public class IPCTestActivity extends BaseActivity {
private final String TAG = this.getClass().getSimpleName();

@BindView(R.id.tv_result)
TextView mTvResult;
@BindView(R.id.btn_add_person)
Button mBtnAddPerson;
@BindView(R.id.et_msg_content)
EditText mEtMsgContent;
@BindView(R.id.btn_send_msg)
Button mBtnSendMsg;

/**
* 客户端的 Messenger
*/
Messenger mClientMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(final Message msg) {
if (msg != null && msg.arg1 == ConfigHelper.MSG_ID_SERVER){
if (msg.getData() == null){
return;
}

String content = (String) msg.getData().get(ConfigHelper.MSG_CONTENT);
LogUtils.d(TAG, "Message from server: " + content);
}
}
});

//服务端的 Messenger
private Messenger mServerMessenger;

private ServiceConnection mMessengerConnection = new ServiceConnection() {
@Override
public void onServiceConnected(final ComponentName name, final IBinder service) {
mServerMessenger = new Messenger(service);
}

@Override
public void onServiceDisconnected(final ComponentName name) {
mServerMessenger = null;
}
};

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aidl);
ButterKnife.bind(this);
bindAIDLService();
bindMessengerService();
}

private void bindMessengerService() {
Intent intent = new Intent(this, MessengerService.class);
bindService(intent, mMessengerConnection, BIND_AUTO_CREATE);
}

@OnClick(R.id.btn_send_msg)
public void sendMsg() {
String msgContent = mEtMsgContent.getText().toString();
msgContent = TextUtils.isEmpty(msgContent) ? "默认消息" : msgContent;

Message message = Message.obtain();
message.arg1 = ConfigHelper.MSG_ID_CLIENT;
Bundle bundle = new Bundle();
bundle.putString(ConfigHelper.MSG_CONTENT, msgContent);
message.setData(bundle);
message.replyTo = mClientMessenger;     //指定回信人是客户端定义的

try {
mServerMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}

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

}


运行效果



发送后,服务端进程收到消息:



然后进行了答复:



使用小结

可以看到客户端的操作主要有 3 步:

创建客户端的
Messenger
,传递一个
Handler
处理消息

bindService
,在
ServiceConnection
回调中拿到服务端的
Messenger


发送消息

Message.obtain()
消息池里获取一个空闲消息对象

使用
message.setData(bundle)
设置数据

指定回信的信使
message.replyTo = mClientMessenger


调用服务端信使,发射!
mServerMessenger.send(message)


总结

Messenger 对 AIDL 进行了封装,也就是对 Binder 的封装,我们可以使用它的实现来完成基于消息的跨进程通信,就和使用 Handler 一样简单。

使用步骤:

客户端创建一个
Messenger
,传递一个 Handler 处理消息

服务端也一样

如果需要回信,给
Message
设置一个用于回信的 Messenger 即可:

message.replyTo = mClientMessenger;


客户端在调用
send()
方法之后,就会走 Binder 跨进程通信机制 ,最后到服务端的 Handler 中得到处理。

借用鸿洋的图表达一下:

使用时和 Binder 一样,建议在四大组件中使用,那样可以提高优先级,让系统不随便关闭当前进程。

代码地址

Thanks

https://developer.android.com/reference/android/os/Messenger.html

http://book2s.com/java/src/package/android/os/imessenger.html

http://www.jianshu.com/p/af8991c83fcb

http://blog.csdn.net/lmj623565791/article/details/47017485
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: