//这里服务端Service是运行在单独的进程中的 android:process=“:other”
class MessengerService : Service() {
private lateinit var mMessenger: Messenger
override fun onBind(intent: Intent): IBinder {
log(TAG, “onBind~”)
//传入Handler实例化Messenger
mMessenger = Messenger(IncomingHandler(this))
//将Messenger中的binder返回给客户端,让它可以远程调用
return mMessenger.binder
}
//处理客户端传递过来的消息(Message) 并根据what决定下一步操作
internal class IncomingHandler(
context: Context,
private val applicationContext: Context = context.applicationContext
) : Handler(
Looper.getMainLooper()
) {
override fun handleMessage(msg: Message) {
when (msg.what) {
MSG_SAY_HELLO -> {
Toast.makeText(applicationContext, “hello!”, Toast.LENGTH_SHORT).show()
log(TAG, “hello!”)
}
else -> super.handleMessage(msg)
}
}
}
}
2.2.2 客户端
客户端进程中,首先是需要绑定远程Service.绑定完成之后,在onServiceConnected()
中拿到远程Service返回的IBinder对象,用此IBinder对象实例化客户端这边的Messenger.有了这个Messenger,就可以通过这个Messenger往服务端发送消息了.示例代码如下:
class MessengerActivity : TitleBarActivity() {
/** 与服务端进行沟通的Messenger */
private var mService: Messenger? = null
/** 是否已bindService */
private var bound: Boolean = false
private val mServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
mService = Messenger(service)
bound = true
}
override fun onServiceDisconnected(name: ComponentName?) {
mService = null
bound = false
}
}
override fun getThisTitle(): CharSequence {
return “Messenger”
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_messenger)
btnConnect.setOnClickListener {
connectService()
}
btnSayHello.setOnClickListener {
sayHello()
}
}
private fun sayHello() {
if (!bound) {
return
}
//创建,并且发送一个message给服务端 Message中what指定为MSG_SAY_HELLO
val message = Message.obtain(null, MSG_SAY_HELLO, 0, 0)
try {
mService?.send(message)
} catch (e: RemoteException) {
e.printStackTrace()
}
}
private fun connectService() {
Intent().apply {
action = “com.xfhy.messenger.Server.Action”
setPackage(“com.xfhy.allinone”)
}.also { intent ->
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE)
}
}
override fun onStop() {
super.onStop()
if (bound) {
unbindService(mServiceConnection)
bound = false
}
}
}
通过示例代码我们知道客户端通过Messenger与服务端进行通信时,必须将数据放入Message中,Messenger和Message都实现了Parcelable接口,因此是可以跨进程传输的.Message只能通过what、arg1、arg2、Bundle以及replyTo来承载需要传递的数据,如果需要传递Serializable或者Parcelable的对象则可以放进Bundle里面进行传递,Bundle还支持其他大量的数据类型.
2.2.3 服务端向客户端发送消息
有时候我们需要客户端能响应服务端发送的消息,此时我们只需要在上面的示例的基础上简单修改即可.
服务端这边每次收到消息,都回复一条消息给客户端,方便测试
internal class IncomingHandler : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
when (msg.what) {
MSG_SAY_HELLO -> {
log(TAG, “hello!”)
//客户端的Messenger就是放在Message的replyTo中的
replyToClient(msg, “I have received your message and will reply to you later”)
}
MSG_TRANSFER_SERIALIZABLE -> log(TAG, “传递过来的对象: ${msg.data?.get(“person”)}”)
else -> super.handleMessage(msg)
}
}
private fun replyToClient(msg: Message, replyText: String) {
val clientMessenger = msg.replyTo
val replyMessage = Message.obtain(null, MSG_FROM_SERVICE)
replyMessage.data = Bundle().apply {
putString(“reply”, replyText)
}
try {
clientMessenger?.send(replyMessage)
} catch (e: RemoteException) {
e.printStackTrace()
}
}
}
而客户端这边需要做出响应,则还需在客户端创建一个Messenger,并为其创建一个Handler用于接收服务端传递过来的消息.在客户端发送消息时,需要将Message#replyTo
设置为客户端的Messenger. 服务端拿到这个Messanger才能回复消息.
/** 客户端这边的Messenger */
private var mClientMessenger = Messenger(IncomingHandler())
class IncomingHandler : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
when (msg.what) {
MSG_FROM_SERVICE -> {
log(TAG, “Received from service: ${msg.data?.getString(“reply”)}”)
}
else -> super.handleMessage(msg)
}
}
}
private fun sayHello() {
if (!bound) {
return
}
//创建,并且发送一个message给服务端 Message中what指定为MSG_SAY_HELLO
val message = Message.obtain(null, MSG_SAY_HELLO, 0, 0)
//注意 这里是新增的
message.replyTo = mClientMessenger
message.data = Bundle().apply {
putSerializable(“person”, SerializablePerson(“张三”))
}
try {
mService?.send(message)
} catch (e: RemoteException) {
e.printStackTrace()
}
}
服务端调用sayHello()
之后,输出日志如下:
2020-12-31 11:59:40.420 29702-29702/com.xfhy.allinone D/xfhy_messenger: hello!
2020-12-31 11:59:40.421 29649-29649/com.xfhy.allinone D/xfhy_messenger: Received from service: I have received your message and will reply to you later
日志里面明显看到是2个进程,所以现在是达到是双向通信的目的.Messenger的使用大概就是这些了,下面是Messenger的大致工作原理图
//todo xfhy 插图 Messenger的工作原理 Android开发艺术探索(P93)
3.1 客户端->服务端通信
服务端
当客户端到服务端单向通信时,我们来看一下大致的原理.首先是服务端这边在onBind方法中返回了Messenger的binder对象
override fun onBind(intent: Intent): IBinder {
//传入Handler实例化Messenger
mMessenger = Messenger(IncomingHandler())
//将Messenger中的binder返回给客户端,让它可以远程调用
return mMessenger.binder
}
我们看下Messenger里面的binder是什么:
private final IMessenger mTarget;
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
public IBinder getBinder() {
return mTarget.asBinder();
}
从Messenger的构造方法(IMessenger.Stub.asInterface()
)可以看出它底层应该是使用的AIDL搞的.getBinder()其实是将调用了mTarget.asBinder()
,而mTarget是我们传进来的Handler里面拿出来的,跟进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);
}
}
原来IMessenger是Handler的内部类MessengerImpl,它只有一个send方法.结合上面Messenger的源码,我们发现调用Messenger的send方法其实就是调用这里的MessengerImpl的send方法,然后这个send里面将Message转发给Handler#sendMessage()
,最后也就是去了Handler#handleMessage()
里面接收到这个Message.
MessengerImpl是继承自IMessenger.Stub
,这一看就感觉是AIDL文件自动生成的嘛,easy.大胆猜测一下对应的aidl文件应该是IMessenger.aidl
,我们去源码里面找IMessenger.aidl
,果然在frameworks/base/core/java/android/os/IMessenger.aidl
这个位置找到了它.内容如下:
package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger {
void send(in Message msg);
}
根据aidl文件,它自动生成的IMessenger.java
应该长下面这样:
package android.os;
public interface IMessenger extends android.os.IInterface {
/**
- Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements IMessenger {
private static final java.lang.String DESCRIPTOR = “android.os.IMessenger”;
/**
- Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
-
Cast an IBinder object into an android.os.IMessenger interface,
-
generating a proxy if needed.
*/
public static IMessenger asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof IMessenger))) {
return ((IMessenger) iin);
}
return new IMessenger.Stub.Proxy(obj);
}
@Override
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 {
java.lang.String descriptor = DESCRIPTOR;
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;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements IMessenger {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public void send(android.os.Message msg) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((msg != null)) {
_data.writeInt(1);
msg.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_send, _data, null, android.os.IBinder.FLAG_ONEWAY);
} finally {
_data.recycle();
}
}
}
static final int TRANSACTION_send = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void send(android.os.Message msg) throws android.os.RemoteException;
}
这就好办了,这就明摆着说明Messenger底层是基于AIDL实现的.服务端这边这条线: Service#onBind()->mMessenger.getBinder()->Handler#getIMessenger()->MessengerImpl(IMessenger.Stub)
,其实就是和我们使用AIDL一样将IXXX.Stub的子类通过onBind返回回去,客户端绑定的时候好拿到binder对象.接收客户端的消息时,是通过MessengerImpl转发给Handler来完成的,服务端这边定义的那个Handler就可以在handleMessage()
中处理跨进程传递过来的Message,从而理解客户端想要调用什么服务,然后执行相应的逻辑.
客户端
最后
小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
资料⬅专栏获取
T_CALL_TRANSACTION + 0);
}
public void send(android.os.Message msg) throws android.os.RemoteException;
}
这就好办了,这就明摆着说明Messenger底层是基于AIDL实现的.服务端这边这条线: Service#onBind()->mMessenger.getBinder()->Handler#getIMessenger()->MessengerImpl(IMessenger.Stub)
,其实就是和我们使用AIDL一样将IXXX.Stub的子类通过onBind返回回去,客户端绑定的时候好拿到binder对象.接收客户端的消息时,是通过MessengerImpl转发给Handler来完成的,服务端这边定义的那个Handler就可以在handleMessage()
中处理跨进程传递过来的Message,从而理解客户端想要调用什么服务,然后执行相应的逻辑.
客户端
最后
小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
[外链图片转存中…(img-CtEVRTG6-1719085829779)]一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
资料⬅专栏获取