本文主要是介绍Android 进阶10:进程通信之 Messenger 使用与解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
读完本文你将了解:
-
- 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 implementsandroid.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;}@Overridepublic 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() {@Overridepublic 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@Overridepublic 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() {@Overridepublic 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);}}});//服务端的 Messengerprivate Messenger mServerMessenger;private ServiceConnection mMessengerConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(final ComponentName name, final IBinder service) {mServerMessenger = new Messenger(service);}@Overridepublic void onServiceDisconnected(final ComponentName name) {mServerMessenger = null;}};@Overrideprotected 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();}}@Overrideprotected 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
这篇关于Android 进阶10:进程通信之 Messenger 使用与解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!