Android AIDL跨进程通信

news2024/9/20 18:42:19

一、前言


  • 什么是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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/638877.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【集群】Haproxy搭建Web群集

文章目录 一、Haproxy 相关概念1. Haproxy 的概述2. Haproxy 的主要特性3. 常见的 Web 集群调度器4. 常见的应用分析4.1 LVS 应用4.2 Haproxy 应用4.3 LVS、Nginx、Haproxy的区别 5. Haproxy 调度算法原理5.1 roundrobin5.2 static-rr5.3 leastconn5.4 source5.5 uri5.6 url_pa…

【1 TypeScript - TypeScript语法的类型】

1 认识TypeScript 主要是为了解决类型检查的痛点.是拥有类型的JavaScript超集,虽然编写的是Typescript,但是最终仍然会编译成JavaScript代码. 2 TypeScript的运行环境 使用ts-node 3 变量的声明 变量的类型推导&#xff08;推断&#xff09; 4 JavaScript类型 – Array类…

ThinkPHP5源码阅读-类的自动加载register与autoload的实现

文章目录 前言如何下载ThinkPHP5源码关于自动加载类类的准备进入base.phpLoader::register() 注册自动加载函数对composer 的支持对think和trait的支持对extend目录的支持 类的加载autoload方法class_alias的定义和使用findFile 查找类 作业&#xff1a;自定义一个可以被自动类…

Java设计模式—责任链模式(Chin of Responsibility)

目录 前言 一、责任链模式的简介 二、责任链模式的概念 三、责任链模式的作用 四、责任链模式的优、缺点 1.责任链模式的优点 2.责任链模式的缺点 五、责任链模式的应用场景 六、代码案例 UML类图 1.定义一个请求枚举类 2.定义一个请求类 3.定义一个抽象处理接口 4、…

TS中any与unknown详解,示例

文章目录 前言一、一个示例二、示例目的1、功能描述2、主要区别3、代码实现 总结 前言 本片文章主要是在写ts时遇到不知道类型&#xff0c;很容易就想到用any可以解决一切&#xff0c;但这样写并不好。所以今天就总结学习一下&#xff0c;比较好的处理任意类型的unknown。 一、…

2023年最新网络安全入门指南,保姆级教程!啃完这篇就够了

一、网络安全学习的误区 1.不要试图以编程为基础去学习网络安全 不要以编程为基础再开始学习网络安全&#xff0c;一般来说&#xff0c;学习编程不但学习周期长&#xff0c;且过渡到网络安全用到编程的用到的编程的关键点不多。一般人如果想要把编程学好再开始学习网络安全往…

大气污染扩散模型Calpuff教程

详情点击链接&#xff1a;大气污染扩散模型Calpuff教程一&#xff0c;Calpuff 1.Calpuff模型 2、Calpuff模型基础 3、Calpuff模型下载安装 1&#xff09;Calpro系统安装 2&#xff09;安装环境要求 3&#xff09;需安装的辅助软件二&#xff0c;数据预处理 1.网格设置 …

Vue3-04-生命周期

Vue 的生命周期描述组件从创建到销毁的全过程。Vue3 和 Vue2 的生命周期钩子非常像&#xff0c;我们仍然可以在相同的场景下使用相同的钩子函数。 Vue3 在设计时对先前的版本进行了向下兼容&#xff0c;如果你的项目还在使用选项式 API 进行构建&#xff0c;那么不需要修改生命…

【stable diffusion】图片批量自动打标签、标签批量修改(BLIP、wd14)用于训练SD或者LORA模型

参考&#xff1a; B站教学视频【&#xff1a;AI绘画】新手向&#xff01;Lora训练&#xff01;训练集准备、tag心得、批量编辑、正则化准备】官方教程&#xff1a;https://github.com/darkstorm2150/sd-scripts/blob/main/docs/train_README-en.md#automatic-captioning 一、…

Springboot全文链路id,并ELK搭建部署整合全文链路id

Springboot全文链路id,并ELK搭建部署整合全文链路id 1.docker-compose.yaml部署 version: 3 services:elasticsearch:image: elasticsearch:7.13.2container_name: elasticsearchenvironment:- "cluster.nameelasticsearch" #设置集群名称为elasticsearch- "d…

[笔记]C++并发编程实战 《五》C++内存模型和原子类型操作

文章目录 前言第5章 C内存模型和原子类型操作5.1 内存模型基础5.1.1 对象和内存位置5.1.2 对象、内存位置和并发5.1.3 修改顺序 5.2 C中的原子操作和原子类型5.2.1 标准原子类型 总结 前言 第5章 C内存模型和原子类型操作 本章主要内容&#xff1a; C11内存模型详解标准库提…

【Docker】子系统与其相关名词的界定、Control Groups等详细讲解

前言 Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。 &#x1f4d5;作者简介&#xff1a;热…

回收旧物系统平台开发的功能

1、定位服务 为了方便用户寻找最近的废品回收点&#xff0c;小程序应该提供位置服务和导航功能。 2、垃圾分类知识普及 用户可以查看所有垃圾分类知识&#xff0c;每种物品属于哪一个类型的垃圾分类。一目了然。相当于一本活字典&#xff0c;用户可以随时翻看查阅垃圾分类的…

人工智能(pytorch)搭建模型11-pytorch搭建DCGAN模型,一种生成对抗网络GAN的变体实际应用

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能(pytorch)搭建模型11-pytorch搭建DCGAN模型&#xff0c;一种生成对抗网络GAN的变体实际应用&#xff0c;本文将具体介绍DCGAN模型的原理&#xff0c;并使用PyTorch搭建一个简单的DCGAN模型。我们将提供模型…

java+openlayer实现大气污染扩散模拟反演

一、模拟参数及效果 二、应用背景 大气污染是当今社会面临的一个重要问题。随着工业化和城市化的进程&#xff0c;大气污染问题变得越来越严重。为了更好地应对这个问题&#xff0c;许多科学家和研究人员开始探索大气污染扩散反演技术。 大气污染扩散反演技术是一种通过数学模…

给软件测试人的一封信,全网最佳“指路明灯“

一、一招鲜吃遍天下 你需要有一个核心技能。这个技能至少达到远超你的同事&#xff08;包括开发岗位的同事的&#xff09;平均水平。最好达到业界领先水平&#xff0c;且这个核心技能需要不断打磨提高。比如&#xff0c;我选择的核心技能是使用Python写代码。这个核心技能可以…

3.2 基于Java配置类整合SSM框架实现用户登录

一、基于Java配置类整合SSM框架实现用户登录 1、创建Maven项目 Maven项目 - SSMLoginNew 单击【Finish】按钮 2、添加相关依赖 在pom.xml文件里添加相关依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache…

Kubernetes 1.27 加快 Pod 启动速度

如何在大型集群中加快节点上的 Pod 启动&#xff1f;这是企业集群管理员常常会面临的问题。 这篇博文重点介绍了从 kubelet 一侧加快 Pod 启动的方法。此方法不涉及通过 kube-apiserver 由 controller-manager 创建 Pod 所用的时间段&#xff0c;也不包含 Pod 的调度时间或在其…

电脑最牛逼的截图方式

1.电脑桌面上空白的地方新建一个文本文档&#xff0c;将后缀名修改为bat&#xff0c;截图如下&#xff1a; 2.右键点击该文档编辑&#xff0c;在编辑界面输入start snippingtool&#xff0c;点击保存之后关闭该文档。 3.双击该文档&#xff0c;在模式里面选择响应的截图方式即可…

MySQL IDE与pymysql模块

一、IDE工具介绍 生产环境还是推荐使用mysql命令行&#xff0c;但为了方便我们测试&#xff0c;可以使用IDE工具 在此我们推荐使用Navicat软件或pycharm来连接数据库,这样就能更详细直观地查询数据 掌握&#xff1a; #1. 测试链接数据库 #2. 新建库 #3. 新建表&#xff0c;新增…