Kotlin--›IPC跨进程通信之Messager(双向通信)

Android跨进程通信有很多种方式, 具体的大家百度一下就知道了. AIDL就是其中一种;

本文介绍AIDL系统轻量封装Messager的使用.

官网文档:https://developer.android.google.cn/guide/components/bound-services邀请您先阅读


涉及到的类

类名作用
Service进程载体
Handler处理消息, 关联MessageMessenger的通道
Message需要发送的消息实体, 传输数据的载体
Messenger发送消息, 通信的实体类, 用来send Message
Parcelable自定义需要传输的数据

1.服务端编写

class RemoteService : Service() {

    val remoteHandler: Handler = object : Handler() {
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)

            //注意此处, 必须的设置, 否则自定义的MsgBean类, ClassNotFoundException异常
            msg.data.classLoader = RemoteService.javaClass.classLoader

            val bean:MsgBean = msg.data.getParcelable<MsgBean>("data")

            if (msg.what == 3) {
                //测试死循环, 不会出现anr
                Thread.sleep(10_000)
            }

            //收到消息后, 可以通过replyTo对象, 回复客户端.
            msg.replyTo?.let {

                //java.lang.RuntimeException: Can't marshal callbacks across processes.
//                it.send(Message.obtain(null) {
//                    L.e("runnable")
//                })

                sendText(it, 10_001, "服务端已收到消息.${msg.what}")
            }
        }
    }

    private fun sendText(messenger: Messenger, what: Int, text: String) {
        messenger.send(Message.obtain(null, what).apply {
            replyTo = remoteMessenger //用来答复的Messenger
            data = Bundle().apply {
                putParcelable("data", MsgBean(text)) //数据建议放在 Bundle中
            }
        })
    }

    private val remoteMessenger: Messenger

    init {
        remoteMessenger = Messenger(remoteHandler)
    }

    override fun onBind(p0: Intent?): IBinder {
        return remoteMessenger.binder
    }
}

几点需要注意的:
1. 静态数据在服务端修改后, 客户端获取不到修改后的值
2. 自定义的数据, 尽量使用 Bundle 包一层
3. Bundle需要设置classLoader, 否则会出现ClassNotFoundException

不要忘了在AndroidManifest.xml声明:

<service
   android:name=".RemoteService"
   android:process=":remote"/>

如果android:process的名字, 有:号, 则这个进程和主进程是 父子关系 否则就是 兄弟关系

2.客户端编写

基础的对象声明:

val localHandler = object : Handler() {
    override fun handleMessage(msg: Message) {
        super.handleMessage(msg)
        L.e("客户端: handleMessage ->${RemoteService.test_static_data} ${msg.what} ${msg.obj}")

        msg.data.classLoader = classLoader //注意:同样的设置

        showText("收到服务端消息:${RemoteService.test_static_data} ${msg.what} ${msg.obj} ${msg.data.getParcelable<MsgBean>("data")}")
    }
}

val localMessenger = Messenger(localHandler)

var remoteMessenger: Messenger? = null

启动服务端:

val remoteServiceIntent = Intent(this, RemoteService::class.java)
val remoteCon = object : ServiceConnection {
    override fun onServiceDisconnected(p0: ComponentName?) {
        L.e("call: onServiceDisconnected -> $p0")

        showText("onServiceDisconnected_${p0}")

        remoteMessenger = null
    }

    override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
        L.e("call: onServiceConnected -> $p0 $p1")
        showText("onServiceConnected_${p0}")

        remoteMessenger = Messenger(p1)
        sendText(1, "客户端连接成功...")
    }
}
bindService(remoteServiceIntent, remoteCon, Service.BIND_AUTO_CREATE)

发送消息:

private fun sendText(what: Int, text: String) {
  remoteMessenger?.send(Message.obtain(null, what).apply {
      replyTo = localMessenger
      data = Bundle().apply {
          putParcelable("data", MsgBean(text))  //用Bundle包一层
      }
  })
}

源码地址: https://github.com/angcyo/IPC_Messager

也许你还想学习更多, 来我的群吧, 我写代码的能力, 远大于写文章的能力:

联系作者

点此快速加群

请使用QQ扫码加群, 小伙伴们都在等着你哦!

关注我的公众号, 每天都能一起玩耍哦!

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:上身试试 返回首页