当前位置: 首页 > news >正文

【进程间通信】

名称优点缺点适用场景
Bundle简单易用只能传输Bundle支持的数据类型四大组件间的进程间通信
文件共享简单易用不适用高并发场景,并且无法做到进程间即时通信适用于无关发的情况下,交换简单的数据,对实时性要求不高的场景。
AIDL功能强大,支持一对多实时并发通信使用稍复杂,需要处理好线程间的关系一对多通信且有RPC需求
Messenger功能一般,支持一对多串行通信,支持实时通信不能很好地处理高并发的情形,不支持RPC,由于数据通过Message传输,因此只能传输Bundle支持的数据类型低并发的一对多实时通信,无RPC需求,或者无需要返回结果的RPC需求
ContentProvider支持一对多的实时并发通信,在数据源共享方面功能强大,可通过Call方法扩展其它操作可以理解为受约束的AIDL,主要提供对数据源的CRUD操作一对多的进程间数据共享
BroadcastReceiver操作简单,对持一对多实时通信只支持数据单向传递,效率低且安全性不高一对多的低频率单向通信
Socket功能强大,可通过网络传输字节流,支持一对多实时并发通信实现细节步骤稍繁琐,不支持直接的RPC网络间的数据交换

由于不同的进程拥有不同的数据空间,所以无论是应用内还是应用间,均无法通过共享内存来实现进程间通信。

[1] 使用Bundle ( 搬豆 ) 的方式

在Android中三大组件(Activity,Service,Receiver)都支持在Intent中传递Bundle数据,由于Bundle实现了Parcelable接口(一种特有的序列化方法),所以它可以很方便的在不同的进程之间进行传输。当在一个进程中启动另外一个进程的Activity,Service,Receiver时,可以在Bundle中附加需要传输给远程的进程的信息,并通过Intent发送出去。

putExtras(Bundle data):向Intent中放入所需要“携带”的数据包。

Bundle getExtras():取出Intent中所“携带”的数据包。

注意:我们传输的数据必须基本数据类型或者能够被序列化。

利用Bundle进行进程间通信,只能是单方向的简单数据传输,使用有一定的局限性。

[2] 使用文件共享的方式

**文件共享:**将对象序列化之后保存到文件中,在通过反序列,将对象从文件中读取出来。此方式对文件的格式没有具体的要求,可以是文件、XML、JSON等。

**文件共享方式也存在着很大的局限性,如并发读/写问题,如读取的数据不完整或者读取的数据不是最新的。**文件共享适合在对数据同步要求不高的进程间通信,并且要妥善处理并发读/写的问题。

[3] 使用Messenger的方式

​ 我们也可以通过Messenger来进行进程间通信,在Messenger中放入我们需要传递的数据,实现进程间数据传递。Messenger只能传递Message对象,Messenger是一种轻量级的IPC方案,它的底层实现是AIDL。

服务端

(1):创建Service;

(2):构造Handler对象,实现handlerMessage方法;

(3):通过Handler对象,构造Messenger对象;

(4):通过Service的onBind()返回这个Messenger对象底层的Binder对象;

客户端

(1):创建Actvity;

(2):绑定远程进程Service;

(3):创建ServiceConnection,监听绑定服务的回调;

(4):通过onServiceConnected()方法的参数,构造客户端Messenger对象;

(5):通过Messenger向服务端发送消息。

Messenger的工作原理图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VLHEuybX-1653288552921)(X:\Users\xu\AppData\Roaming\Typora\typora-user-images\image-20200921093824422.png)]

Messenger内部消息处理使用Handler实现的,所以它是以串行的方式处理客服端发送过来的消息的,如果有大量的消息发送给服务器端,服务器端只能一个一个处理,如果并发量大的话用Messenger就不合适了,而且Messenger的主要作用就是为了传递消息,很多时候我们需要跨进程调用服务器端的方法,这种需求Messenger就无法做到了。

[4] 使用AIDL的方式

AIDL(Android Interface Definition Language)是一种IDL语言,用于生成可以在Android设备上两个进程之间进行进程间通信(IPC)的代码。

如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。AIDL是IPC的一个轻量级实现,Android也提供了一个工具,可以自动创建Stub(类架构,类骨架)。在应用间通信时,需要以下几步:

(1):定义一个AIDL接口;

(2):为远程服务(Service)实现对应Stub;

(3):将服务“暴露”给客户程序使用;

只有当你允许来自不同的客户端访问你的服务并且需要处理多线程问题时你才必须使用AIDL,其他情况下都可以选择其他方法。AIDL是处理多线程、多客户端并发访问的,而Messenger是单线程处理。

[5] 使用ContentProvider的方式

ContentProvider(内容提供者)是Android中的四大组件之一,为了在应用程序之间进行数据交换,Android提供了ContentProvider,ContentProvider是不同应用之间进行数据交换的API,一旦某个应用程序通过ContentProvider暴露了自己的数据操作的接口,那么不管该应用程序是否启动,其他的应用程序都可以通过接口来操作接口内的数据,包括数据的增、删、改、查等操作。

开发一个ContentProvider:

(1):定义自己的ContentProvider类,该类集成ContentProvider基类;

(2):在AndroidMainfest.xml中注册这个ContentProvider,注册时要给ContentProvider绑定一个域名;

(3):当注册好这个ContentProvider后,其他应用就可以访问ContentProvider暴露出来的数据了。

ContentProvider只是暴露出来可供其他应用操作的数据,其他应用则需要通过ContentProvider来操作。

使用ContentResolver操作数据:

(1):调用Activity的getContentResolver()获取ContentResolver对象;

(2):根据调用的ContentResolver的insert()、delete()、update()和query()方法操作数据库。

[6] 使用广播接收者(Broadcast)的方式

广播是一种被动跨进程通信方式。当某个程序向系统发送广播时,其他的应用程序只能被动地接收广播数据。

Broadcast Receiver本质上是一个系统级的监听器,它专门监听各个程序发出的Broadcast,因此它拥有自己的进程,只要存在与之匹配的Intent被广播出来,Broadcast Receiver总会被激发。只要注册了某个广播之后,广播接收者才能收到该广播。广播注册的一个行为是将自己感兴趣的Intent Filter注册到Android系统的AMS(Activity Manager Service)中,里面保存了一个Intent Filter列表。广播发送者将Intent Filter的action行为发送到AMS中,然后遍历AMS中的Intent Filter列表,看谁订阅了该广播,然后将消息遍历发送到注册了相应的Intent Filter或者Service中—也就是说:会调用抽象方法onReceive()方法。其中AMS起到了中间桥梁的作用。

程序启动Broadcast Receiver:

(1):创建需要启动的Broadcast Receiver的intent;

(2):调用Context的sendBroadcast()或者sendOrderBroadcast()方法来启动指定的BroadcastReceivert。

每当Broadcast事件发生后,系统会创建对应的Broadcast Receiver实例,并自动触发onReceiver()方法,onReceiver()方法执行完后,BroadcastReceiver实例就会被销毁。

**Tips:**onReceiver()方法中尽量不要做耗时操作,如果onReceiver()方法不能再10秒之内完成事件的处理,Android会认为该进程无响应,也就弹出我们熟悉的ANR。

[7] 使用Socket的方式

Socket也是实现进程间通信的一种方式,Socket也称为“套接字”(网络通信中概念),通过Socket也可以实现跨进程通信,Socaket主要还是应用在网络通信中。

[8] Android 进程间通信不同方式的比较
  • Bundle:四大组件间的进程间通信方式,简单易用,但传输的数据类型受限。
  • 文件共享: 不适合高并发场景,并且无法做到进程间的及时通信。
  • Messenger: 数据通过Message传输,只能传输Bundle支持的类型。
  • ContentProvider:android 系统提供的,简单易用,但使用受限,只能根据特定规则访问数据。
  • AIDL:功能强大,支持实时通信,但使用稍微复杂。
  • Socket:网络数据交换的常用方式。

相关文章:

  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • Android知识点总结
  • 无锁和无等待的定义和例子
  • Leetcode Hot100
  • SpringMVC 源码深度解析lt;context:component-scangt;(扫描和注冊的注解Bean)
  • Django中render_to_response和render的区别(转载)
  • 【烈日炎炎战Android】
  • BZOJ 3168 Heoi2013 钙铁锌硒维生素 矩阵求逆+匈牙利算法
  • 【自定义view-水波纹动画】
  • android studio 修改gradle引用本地文件
  • 【烈日炎炎战后端】JAVA基础(3.4万字)
  • GZFramework代码生成器插件使用教程
  • 【烈日炎炎战后端】JAVA集合(1.8万字)
  • CSS3 伪类选择器 nth-child() 的用法
  • poi导入excel
  • angular学习第一篇-----环境搭建
  • javascript 总结(常用工具类的封装)
  • Js基础知识(一) - 变量
  • js如何打印object对象
  • Material Design
  • Python代码面试必读 - Data Structures and Algorithms in Python
  • session共享问题解决方案
  • SQL 难点解决:记录的引用
  • 飞驰在Mesos的涡轮引擎上
  • 诡异!React stopPropagation失灵
  • 基于web的全景—— Pannellum小试
  • 前端技术周刊 2018-12-10:前端自动化测试
  • 区块链将重新定义世界
  • 深度学习在携程攻略社区的应用
  • 使用API自动生成工具优化前端工作流
  • 世界上最简单的无等待算法(getAndIncrement)
  • 双管齐下,VMware的容器新战略
  • 一起参Ember.js讨论、问答社区。
  • - 语言经验 - 《c++的高性能内存管理库tcmalloc和jemalloc》
  • RDS-Mysql 物理备份恢复到本地数据库上
  • ​520就是要宠粉,你的心头书我买单
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • (2.2w字)前端单元测试之Jest详解篇
  • (4)logging(日志模块)
  • (二)Pytorch快速搭建神经网络模型实现气温预测回归(代码+详细注解)
  • (附源码)springboot教学评价 毕业设计 641310
  • (附源码)ssm教材管理系统 毕业设计 011229
  • (紀錄)[ASP.NET MVC][jQuery]-2 純手工打造屬於自己的 jQuery GridView (含完整程式碼下載)...
  • (三维重建学习)已有位姿放入colmap和3D Gaussian Splatting训练
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • (转)ObjectiveC 深浅拷贝学习
  • *ST京蓝入股力合节能 着力绿色智慧城市服务
  • ./configure,make,make install的作用(转)
  • .gitignore文件—git忽略文件
  • .NET 药厂业务系统 CPU爆高分析
  • .Net 中Partitioner static与dynamic的性能对比
  • .NET/C# 避免调试器不小心提前计算本应延迟计算的值
  • .NET/C# 判断某个类是否是泛型类型或泛型接口的子类型
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)
  • @SuppressWarnings(unchecked)代码的作用