Android AIDL跨进程通信

一、前言


  • 什么是AIDL?
  • AIDL用来做什么的?
  • 怎么使用AIDL?

AIDL是Android的一种接口定义语言,语法跟java接口定义类似,文件格式为 .aidl 非 .java 。AIDL主要是用来实现跨进程通信,AIDL的本质也是通过Binder机制实现的,最终也会通过绑定同一个远程服务来实现通信。下面我写了两个Demo,让DemoB发送消息,DemoA能显示在界面上,示例:

二、DemoA(服务端)

1、创建AIDL文件   

  • 在main下先创建个aidl文件夹,在此目录右键new AIDL文件IChatAidlInterface.aidl,As会自动在aidl文件夹下添加一个包目录
  •  IChatAidlInterface.aidl内容如下
    // IChatAidlInterface.aidl
    package com.yufs.demoa;
    
    // 定义AIDL接口文件
    
    interface IChatAidlInterface {
        //添加好友
        void addFriends(String remark);
        //发送消息
        void sendMsg(String content);
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
                double aDouble, String aString);
    }
  • build一下

  • 在如下目录会自动生成一个java对应的接口类,内部有一个抽象的Sub类继承自Binder,还有一个代理类Proxy实现了当前接口

  •  

2、创建本地的业务实现类ChatAidlImpl,继承自IChatAidlInterface.Stub(),

class ChatAidlImpl:IChatAidlInterface.Stub() {
    var messenger: Messenger?=null
    companion object{
        const val TAG = "yufs"
    }
    override fun addFriends(remark: String) {
        Log.e(TAG,"收到添加好友请求:$remark")
        val msg =Message.obtain()
        msg.what = WHAT_ADD_FRIEND_KEY
        val bundle = Bundle()
        bundle.putString(CONTENT_KEY,remark)
        msg.data = bundle
        messenger?.send(msg)
    }

    override fun sendMsg(content: String) {
        Log.e(TAG,"收到一条消息:$content")
        val msg =Message.obtain()
        msg.what = WHAT_MSG_KEY
        val bundle = Bundle()
        bundle.putString(CONTENT_KEY,content)
        msg.data = bundle
        messenger?.send(msg)
    }

    override fun basicTypes(
        anInt: Int,
        aLong: Long,
        aBoolean: Boolean,
        aFloat: Float,
        aDouble: Double,
        aString: String?
    ) {

    }

}

在上面代码中,我们接收到DemoB发送的消息后并通过Messenger转发消息通知本地更新UI,这里也涉及到一个跨进程通信,是发生在DemoB中的一个远程服务通知本地UI更新

 3、创建远程服务ChatService,并重写onBind,返回上面实现类ChatAidlImpl的实例对象

  • class ChatService:Service() {
        companion object{
            const val MESSENGER = "messenger"
        }
        private val chatAidlImpl = ChatAidlImpl()
        private var mMessenger: Messenger?=null
        override fun onBind(intent: Intent?): IBinder? {
            mMessenger = intent?.getParcelableExtra(MESSENGER)
            //避免被其他绑定的服务空值覆盖
            mMessenger?.let {
                chatAidlImpl.messenger = mMessenger
            }
            return chatAidlImpl
        }
    }

  • 并在manifest文件中注册
  •        <!--注册服务-->
            <service android:name=".service.ChatService"
                android:exported="true"
                android:process=":remote"
                >
                <!--允许通过隐式意图激活绑定服务-->
                <intent-filter>
                    <action android:name="com.yufs.demoa.service.ChatService"/>
                </intent-filter>
            </service>

4、 MainActivity中通过绑定服务来接收显示

class MainActivity : AppCompatActivity() {
    private lateinit var tvContent:TextView
    private lateinit var tvHint:TextView
    private val msgs = mutableListOf<String>()

    private val mHandler = MyHandler(this)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        tvContent = findViewById(R.id.tv_content)
        tvHint = findViewById(R.id.tv_hint)
        val messenger = Messenger(mHandler)
        //绑定服务用于服务中通知当前界面更新UI
        val intent =  Intent(this,ChatService::class.java)
        intent.putExtra(ChatService.MESSENGER,messenger)
        bindService(intent,conn, BIND_AUTO_CREATE)
    }

    class MyHandler(activity: MainActivity) :Handler(Looper.myLooper()!!){
        private val weakReference = WeakReference(activity)
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            when(msg.what){
                WHAT_MSG_KEY ->{
                   val content =  msg.data.getString(CONTENT_KEY)?:""
                    weakReference.get()?.apply {
                        msgs.add(content)
                        Log.e("yufs","size:${msgs},")
                        tvContent.text = msgs.joinToString("\n")
                    }
                }
                WHAT_ADD_FRIEND_KEY ->{
                    val content =  msg.data.getString(CONTENT_KEY)?:""
                    weakReference.get()?.apply {
                        tvHint.visibility = View.VISIBLE
                        tvHint.text = content
                    }
                }
            }
        }
    }

    private val conn = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            Log.e("yufs","服务连接成功")
        }

        override fun onServiceDisconnected(name: ComponentName?) {
        }
    }
}

三、DemoB(客户端)

        DemoB作为客户端,代码就简单得很多了,只需要绑定下DemoA中定义的远程服务,调用AIDL文件下定义的接口方法即可

1、把DemoA中的aidl文件夹完整的复制过来,aidl文件路径两端必须一样,然后build一下,同样会自定生成java对应的接口类

 2、创建服务连接对象,初始化接口IChatAidlInterface代理对象

//声明AIDL接口对象
    private lateinit var iChatAidlInterface: IChatAidlInterface
    private val conn = object :ServiceConnection{
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            //根据实际情况返回 IBinder 的本地对象或其代理对象
            iChatAidlInterface =   IChatAidlInterface.Stub.asInterface(service)
            Log.e(TAG,"服务连接成功")
        }

        override fun onServiceDisconnected(name: ComponentName?) {
            //服务断开回调
        }
    }

 3、通过隐式意图来绑定服务

       其中com.yufs.demoa.service.ChatService为DemoA中注册服务时的action。包名也为DemoA的包名

       //因为跨进程拿不到具体引用,需要指定包名和全路径来绑定远程服务
        val intent = Intent("com.yufs.demoa.service.ChatService")
        //远程应用APP包名,5.0以上需要
        intent.setPackage("com.yufs.demoa")
        //绑定远程服务
        bindService(intent,conn, Context.BIND_AUTO_CREATE)

4、调用接口方法,结果会在DemoA中回调显示

  iChatAidlInterface.sendMsg(content)
  iChatAidlInterface.addFriends("您好,我是张三")

四、总结

        AIDL的文件编写相对来说不是很难,都是定义的一些接口方法,供外部调用。其中,我们通过自定义的远程服务ChatService作为中间组件,在两个应用间都绑定过一次,并且在DemoA中我们的远程服务与Activity的通信是通过Messenger来实现的,Messenger内部也是通过Binder机制将Message从一个进程传递到另一个进程。

五、源码下载

源码下载

https://www.jianshu.com/p/34326751b2c6

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值