Android 进阶10:进程通信之 Messenger 使用与解析
2017-06-01 22:57
776 查看
读完本文你将了解:
Messenger 简介
Messenger 的使用
服务端
客户端
运行效果
使用小结
总结
代码地址
Thanks
前面我们介绍了 AIDL 的使用与原理,这篇文章来介绍下 Android 中另一种 IPC 方式:Messenger。
Messenger 有两个构造函数:
以 Handler 为参数
以 Binder 为参数
看下
这个
这就解释了为什么我们的消息来得时候会出现在
接着再看下 Messenger 另一个重要的方法,
下面我们将写一个客户端跨进程发送消息到服务端的例子,服务端在收到消息后会回复,由于在 Messenger 中一个对象对应一个 Handler,所以我们需要在客户端、服务端分别创建一个 Messenger:
服务端在收到消息后会使用
发送后,服务端进程收到消息:
然后进行了答复:
创建客户端的
发送消息
使用
指定回信的信使
调用服务端信使,发射!
使用步骤:
客户端创建一个
服务端也一样
如果需要回信,给
客户端在调用
借用鸿洋的图表达一下:
使用时和 Binder 一样,建议在四大组件中使用,那样可以提高优先级,让系统不随便关闭当前进程。
http://book2s.com/java/src/package/android/os/imessenger.html
http://www.jianshu.com/p/af8991c83fcb
http://blog.csdn.net/lmj623565791/article/details/47017485
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.htmlhttp://book2s.com/java/src/package/android/os/imessenger.html
http://www.jianshu.com/p/af8991c83fcb
http://blog.csdn.net/lmj623565791/article/details/47017485
相关文章推荐
- Android进程通信之Messenger和AIDL使用详解
- Android 进阶9:进程通信之 AIDL 解析
- Android进程通信之Messenger&AIDL使用详解
- Android中跨进程通信方式之使用AIDL进阶篇
- Android中跨进程通信方式之使用Messenger
- Android使用Messenger实现进程间双向通信
- Android 使用Messenger和Aidl实现跨进程通信
- Android 进程使用 Messenger 通信
- Android 进阶7:进程通信之 AIDL 的使用
- Android基础——Messenger在跨进程通信中的使用
- Android 使用Messenger实现跨进程之间通信
- Android进程通信之Messenger&AIDL使用详解
- android后台服务service全解析(上)--service的使用与本地通信
- Android基础--使用AIDL实现进程间的通信之复杂类型传递
- Android网络开发中如何使用JSON进行网络通信---Android_JSON数据通讯方法解析
- android进程通信之Messenger
- 基础总结篇之四:Service完全解析——使用AIDL实现进程间的通信
- 系出名门Android(10) - HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理
- Messenger:使用消息的跨进程通信
- Messenger:使用消息的跨进程通信