• 使用 Messenger 跨进程通信


    什么是Messenger

    Messenger 也是IPC的方案之一,是基于消息的跨进程通信。基于消息是什么意思?Handler是我们最常用的消息机制,所以 Messenger 对于使用者来说就像是使用 Handler。实际上 Messenger 就是 AIDL 的上层封装而已,它们的底层实现原理都是基于 Binder 的。

    Messenger的使用

    服务端

    import android.app.Service
    import android.content.Intent
    import android.os.Bundle
    import android.os.Handler
    import android.os.IBinder
    import android.os.Looper
    import android.os.Message
    import android.os.Messenger
    import android.util.Log
    
    const val MSG_CLIENT = 0x110
    const val MSG_SERVER = 0x111
    class MessengerService: Service() {
        private val mMessenger = Messenger(object : Handler(Looper.getMainLooper()){
            override fun handleMessage(msg: Message) {
                Log.d("MessengerService", "currentThread ->" + Thread.currentThread().name)
                when(msg.what) {
                    MSG_CLIENT -> {
                        // 除非就是一个简单的整型,可以把值放到 arg 等属性上,否则最好使用 bundle
                        val bundle = msg.data
                        Log.d("MessengerService", "name=${bundle.get("name")}; age=${bundle.get("age")}; height=${bundle.get("height")}")
                        // 服务端封装msg
                        val replyMsg = Message.obtain()
                        replyMsg.what = MSG_SERVER
                        val bundleToC = Bundle()
                        bundleToC.putString("msg",  "我收到了Client的消息")
                        replyMsg.data = bundleToC
                        // 服务端发送给客户端,这里的replyTo是客户端的messenger实例
                        msg.replyTo.send(replyMsg)
                    }
                }
                super.handleMessage(msg)
            }
        });
    
        override fun onBind(intent: Intent?): IBinder? {
            return mMessenger.binder
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    Messenger 本身就是 AIDL 的封装,因此还是通过 serviceonBind() 方法里返回 mMessenger.binder。然后它就像是使用 Handler 一样在 handleMessage() 方法内接收 msg。同样的需要在 AndroidManifest.xml 文件中声明该 service

    <service android:name=".MessengerService"
        android:exported="true">
        <intent-filter>
            <action android:name="com.example.messengerservice">action>
        intent-filter>
    service>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    客户端

    在客户端第一步还是要绑定 Service

    import android.content.ComponentName
    import android.content.Context
    import android.content.Intent
    import android.content.ServiceConnection
    import android.os.Bundle
    import android.os.Handler
    import android.os.IBinder
    import android.os.Looper
    import android.os.Message
    import android.os.Messenger
    import android.os.RemoteException
    import android.util.Log
    import androidx.activity.ComponentActivity
    
    
    class MainActivity: ComponentActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            bindService()
        }
    
        var mMessenger: Messenger? = null
    
        private val mServiceConnection: ServiceConnection = object : ServiceConnection {
            override fun onServiceConnected(name: ComponentName, service: IBinder) {
                mMessenger = Messenger(service)
                Log.i("MainActivity", "onServiceConnected IBinder = $service")
            }
    
            override fun onServiceDisconnected(name: ComponentName) {
                mMessenger = null
            }
        }
    
        private fun bindService() {
            val intent = Intent()
            intent.component = ComponentName("com.example.interprocess", "com.example.service.MessengerService")
            bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE)
        }
    
        fun send() {
            mMessenger?.let { messenger ->
                val msg = Message.obtain()
                msg.what = MSG_CLIENT
                val bundle = Bundle().apply {
                    putString("name", "张三")
                    putInt("age", 22)
                    putString("sex", "男")
                    putString("height", "175cm")
                }
                msg.data = bundle
                msg.replyTo = mClientMessenger
                try {
                    messenger.send(msg)
                } catch (e: RemoteException) {
                    e.printStackTrace()
                }
            }
        }
    
        private val mClientMessenger = Messenger(object : Handler(Looper.getMainLooper()) {
            override fun handleMessage(msg: Message) {
                when(msg.what){
                    MSG_SERVER -> {
                        Log.d("MainActivity", "currentThread ->" + Thread.currentThread().name)
                        Log.d("MainActivity", "server callback = " + msg.data.getString("msg"))
                    }
                }
                super.handleMessage(msg)
            }
        })
    
        override fun onDestroy() {
            super.onDestroy()
            unbindService(mServiceConnection)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    AIDL 使用唯一的差异是将 onServiceConnected()IBinder 参数来构建一个 Messenger 实例。

    最后 Messenger 是通过 send() 方法把 msg 发送出去的,感觉就好像是使用 Handler 发送了消息一样, 真正的数据需要保存到 Bundle 里,这里需要提一点的是如果想给 Bundle 里塞实现了 Parcelable 的对象,会在服务端接受参数时爆出 ClassNotFoundException, 因为两个 App 的 Bundle 是不同类加载器加载的,所以我们使用的时候还是把基本类型数据塞到 bundle 里,这对于大量的复杂数据并不是一个好方式。

    因此基于消息机制的 Messenger 虽然给我们带来了比 AIDL 更便捷的使用和理解,但并不适合管理复杂数据的跨进程通信。

    可以看到上面的代码还给msg.replyTo赋值了一个 mClientMessenger , 这个就是客户端接受消息的 messenger,还记得在服务端回调给客户端的操作就是 msg.replyTo.send(replyMsg),客户端的 messenger 消息处理也是一样的。

    我们在服务端和客户端都打印了一下线程,最后发现接受消息时都已经处于主线程了,这和 messenger 构造函数的 handler 入参有关,handler 指定了主线程的 Looper,那么接收消息时就是在主线程。

    Messenger 原理

    在创建 Messenger 时总是会传入一个 Handler 实例:

    public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }
    
    • 1
    • 2
    • 3

    再进入 Handler 看下:

    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);
        }
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    Handler 里的 MessengerImpl 继承了 IMessenger.Stub,看下 IMessenger

    // IMessenger.aidl
    oneway interface IMessenger {
        void send(in Message msg);
    }
    
    • 1
    • 2
    • 3
    • 4

    这完全就是一个标准的 aidl 接口,只是系统帮我们做了这一层的封装,然后通过 Handler 转化为我们熟悉的消息机制。值得注意这里有 oneway 关键字,说明了 Messenger 就是异步调用,因此 send() 方法不需要返回值。 还有就是参数 Message,既然它能跨进程传递,那么它一定是实现了 Parcelable 接口了,且声明了 aidl 接口:

    // 包路径:/frameworks/base/core/java/android/os/Message.aidl
    package android.os;
    parcelable Message;
    
    // 包路径:/frameworks/base/core/java/android/os/Message.java
    public final class Message implements Parcelable {
    	//...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    还有一个点,Messenger 实现相互通信的方式是设置一个 msg.replyTo 这个变量也是一个 Messenger, 还记得 AIDL 介绍过支持 aidl 接口的传递,所以客户端的 mClientMessenger 能够传递给服务端,然后调用 send() 方法即可回传数据。

    总结

    • Messenger 是基于消息机制的跨进程通信,原理就是对 AIDL 的封装。

    • Messenger不太适合管理复杂数据的跨进程传递。

    • Messenger 天然支持异步的跨进程调用。

    • 无论是客户端还是服务端接收跨进程消息时都处于主线程,免去了切换线程步骤。

    注:本文内容转载自 Messenger 跨进程通信

  • 相关阅读:
    Head First设计模式(阅读笔记)-04.工厂模式
    Python中图像相似性度量方法汇总
    欧洲核子研究中心首次在量子机器学习研究中取得实效
    【EF Core】如何忽略影响导航属性(级联)
    MAC 安装miniconda
    机器学习第五课--广告点击率预测项目以及特征选择的介绍
    【Reinforcement Learning】强化学习基础内容有哪些?
    弘辽科技:网店如何补流量?需要有什么准备?
    ShowDoc部署与应用:文档管理的最佳实践
    4.如何终止线程
  • 原文地址:https://blog.csdn.net/lyabc123456/article/details/132925312