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

上一篇文章介绍了 IPC跨进程通信之Messager(双向通信)

Messenger是系统对aidl一个轻量封装, 方便使用, 但是有一定局限性.

本文介绍直接介绍aidl的使用, 让跨进程通信就跟本地调用一样爽.


准备

  1. 定义调用接口
  2. 创建相应的自定义数据Bean

这里写图片描述
用系统自带的菜单, 创建AIDL文件, 并写上自己的接口定义.
你也可以直接创建File后缀名为aidl,没毛病;

这里写图片描述

需要注意的点
自定义的数据类型, 需要手动import xxx.xxx, 系统不会自动导入.
参数类型还可以使用in out inout标识.参考这里

这里写图片描述

需要注意的点
自定义的数据类, 需要在aidl文件夹中, 创建对应的aidl文件, 并且包名类名需要完全一致.


服务端编写

class RemoteService : Service() {

    /*用来和客户端通信的回调*/
    var callback: ICallback? = null

    private fun sendText(what: Int, text: String) {
        callback?.callback("服务端回调:", MsgBean(text))
    }

    val myAidlInterface = object : IMyAidlInterface.Stub() {
        override fun addCallback(callback: ICallback?) {
            this@RemoteService.callback = callback
        }

        override fun sendMsg(msg: MsgBean?): Int {
            sendText(200, msg?.message ?: "empty")
            return 200
        }

        override fun getMsg(flag: Int): MsgBean {
            return MsgBean("getMsg 测试_flag:$flag")
        }
    }

    override fun onBind(p0: Intent?): IBinder {
        return myAidlInterface //直接返回成员对象
    }
}

相较于Messenger方式, 服务端的代码简洁了很多.

客户端编写

class MainActivity : AppCompatActivity() {

	//声明对象
    var myAidlInterface: IMyAidlInterface? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        val remoteServiceIntent = Intent(this, RemoteService::class.java)
        val remoteCon = object : ServiceConnection {
            override fun onServiceDisconnected(p0: ComponentName?) {
                L.e("call: onServiceDisconnected -> $p0")

                showText("onServiceDisconnected_${p0}")

                myAidlInterface = null
            }

            override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
                L.e("call: onServiceConnected -> $p0 $p1")
                showText("onServiceConnected_${p0}")
				
				//需要通过asInterface的方式,创建对象
                myAidlInterface = IMyAidlInterface.Stub.asInterface(p1)
                sendText(1, "客户端连接成功...")
            }
        }

        findViewById<View>(R.id.bind).setOnClickListener {
            bindService(remoteServiceIntent, remoteCon, Service.BIND_AUTO_CREATE)
        }
    }

    private fun sendText(what: Int, text: String) {
        myAidlInterface?.let {
	        //直接调用对象的方法进行通信,即可.
            it.addCallback(object : ICallback.Stub() {
                override fun callback(str: String?, msg: MsgBean?) {
                    showText("callback 回调:$str $msg")
                }
            })

            val sendMsg = it.sendMsg(MsgBean("${what}_${text}"))
            L.e("call: sendText -> 返回值:$sendMsg  ${it.getMsg(404)}")
        }
    }
}

不要忘了在AndroidManifest.xml声明:

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

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

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

联系作者

点此快速加群

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

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

已标记关键词 清除标记
AIDL的使用步骤是: 创建两个工程,一个为client,一个为server server端在src目录下专门创建一个包用于放置创建的myInterface.aidl接口文件,定义用于通信的抽象方法,然后编译,在gen目录下生成myInterface.java文件,该文件会自动生成内部接口myInterface.Stub;再创建一个Service类,在类中创建myInterface.Stub对象,实现在接口中定义的用于通信的抽象方法; 再重写onBind方法,把Stub对象返回出去(Stub类是IBinder的子类,可以用于client端和server端的通信) 然后在AndroidManifest文件里配置Service类 然后把在server端定义的aidl接口文件复制到client端项目中(连包带文件一起复制,保持client端和server端aidl接口所在包路径一样),在client端的Activity中定义ServiceConnection类对象和server端接口myInterface对象,重写ServiceConnection对象的onServiceConnect,在该方法中获取来自server端的myInterface对象, 现在就可以调用myInterface中的方法(也就是client端调用server端的方法,也就完成了进程间通信) 上面的ServiceConnection要能获取到IBinder对象,还需要client用Intent完成与server端的Service类的绑定 我就卡在这一步了 不管是对server端Service指定Action来让client端启动,还是指定其它东西,就是无法再client端项目里启动server端项目里的Service 有谁知道怎么解决吗? 简而言之,就是如何在当前工程中调用远程Service
©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:上身试试 返回首页