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

Android中的进程间通讯

一、简介

进程间通讯(InterProcess Communication)

指在不同进程之间传播或交换信息,Android是基于Linux 系统的,在Linux 中进程间是不能直接通讯的,IPC就是为了解决这一问题

每个操作系统都有相应的IPC机制,Android中一个进程会对应一个虚拟机实例,不同的虚拟机在内存分配上有不同的地址空间

只有在多进程的环境下才会使用IPC进行通讯

二、使用场景

  • 多模块应用:由于Android应用受到系统的最大内存限制,为了获得更多的内存空间将不同的模块放在不同的线程中,此时需要用到跨进程通信
  • 其它应用:获取其它应用里的数据,比如:获取通讯录和短信

三、实现多进程

Android默认是运行在包名的进程中,可以通过修改AndroidManifest文件,在 application 标签下添加 android:process 属性可以修改Android默认的进程名字

给四大组件(Activity Service Broadcast ContentProvider)设置android:process属性来实现多进程

四、造成的问题

  • 多进程会造成Application的多次创建:当一个组件需要运行在新的进程中时,实际的创建过程就相当于又重新启动了一次应用,就会创建Application。而运行在不同进程中的组件,不仅属于不同的虚拟机,而且其Application也是不同的。
  • 多进程会导致静态成员和单例完全无效:由于不同进程都被分配了独立且不同的虚拟机,其在内存分配上有这不同的地址空间。这就会导致在着一个类的多个副本,各自修改互不影响。
  • 多进程模式下,线程的同步机制也会失效:因为不同的进程,其线程不所属同一内存,那么无论是对象锁还是类锁,锁本身都不是同一个了。
  • 多进程模式下SharedPreferences风险会增大:SharedPreferences底层是通过文件读写实现的,并发操作可能会造成问题。

在不同进程中的组件,如果使用内存来通讯,都会存在隐患或者直接失败。这就是多进程带来的最主要的影响。

五、Android中的跨进程通讯(IPC)

利用Bundle

        在Android开发中,

Activity,Service,Receiver 都支持在 Intent 中传递 Bundle 数据,而 Bundle实现了 Parcelable 接口,以键值对的方式保存数据,可以在不同的进程间进行传输。 可以将其视为一个容器,其支持基本数据类型(String、int、boolean、byte、float、long、double)以及它们对应的数据。当需要传递对象或对象数组时,被传递的对象必须实现Serialiable或Parcelable接口。

Intent intent = new Intent(MainActivity.this, SecondActivity.class);
Bundle bundle = new Bundle();
bundle.putString("msg", "message");
intent.putExtras(bundle);
startActivity(intent);

使用文件共享

        通过共享文件,不同的进程可以使用读写文件的方式交换数据

        不要使用SharedPreferences去做跨进程通讯,原则上它不支持多进程。虽然它本质上也是一个文件,但是由于它在应用运行时会在内存中加载缓存,然而进程间是不能内存共享的,每个进程操作的SharedPreferences都会是一个单独的实例,这就会导致安全性问题,这个问题只能通过多进程间其它的通信方式或者是在确保不会同时操作SharedPreferences数据的前提下使用SharedPreferences来解决。

使用ContentProvider

        ContentProvider提供一种应用管理其自身和其他应用所存储数据的能力,并提供与其他应用共享这些数据的方法。它会封装数据,并提供用于定义数据安全性的机制。无论你是否需要和其他应用分享数据,你都可以使用ContentProvider去访问这些数据,虽然当无需和其他应用共享数据时没必要使用它。系统预置了许多ContentProvider,比如通话记录,通讯录,信息等,只需要通过ContentProvider就可以拿到这些信息。ContentProvider以一个或多个表的形式将数据呈现给外部应用,这些表与关系型数据库中的表类似。行表示提供程序收集的某种类型数据的实例,行中的每一列表示为一个实例所收集的单个数据。

        ContentProvider 的底层数据,可以是 SQLite 数据库,可以是文件,也可以是内存中的数据。

使用场景:

  • 通过实现代码访问其他应用中的现有的ContentProvider用来获得数据;
  • 创建新的ContentProvider,与其他应用共享数据。

使用Messenger

       Messenger是一种轻量级的 IPC 方案,可以在不同进程中传递 Message 对象,它一次只处理一个请求。Messenger通过Handler将Message发送到另一个进程,实现了进程间通信,底层依然是使用了Binder机制,其本质上也是基于AIDL实现的。
        Messenger的缺点:

  • 服务端是以串行的方式在处理消息,不太适合用来出来大量的并发请求。
  • 主要作用是传递消息,不太适合用来跨进程调用方法。

使用方式:构建一个运行在独立进程中的服务端Service,创建Messenger,将Messenger的binder返回给Service的onBind方法。然后接收客户端Messege需要用Handler接收

服务端:

public class MessengerService extends Service {/*** 处理客户端消息,并用于构建Messenger*/private static class MessengerHandler extends Handler {@Overridepublic void handleMessage(@NonNull Message msg) {switch (msg.what) {case 100:System.out.println(msg.getData().getString("data"));sendToClient(msg);break;}}}/*** 给客户度发送消息*/private static void sendToClient(Message message) {Messenger client = message.replyTo;  //通过 message拿到客户传递过来的 Messenger,通过该对象发送message//当然,回传消息还是要通过messageMessage msg = Message.obtain(null, 100);Bundle bundle = new Bundle();bundle.putString("data", "客户端, 我收到你的消息了");msg.setData(bundle);try {client.send(msg);} catch (RemoteException e) {e.printStackTrace();}}/*** 构建Messenger对象*/private final Messenger mMessenger = new Messenger(new MessengerHandler());@Nullable@Overridepublic IBinder onBind(Intent intent) {//将Messenger对象的Binder返回给客户端return mMessenger.getBinder();}
}

注册service

        <service android:name=".messenger.MessengerService"android:process=":messengerprocess"/>

客户端:

class MainActivity : ComponentActivity() {private var mService: Messenger?= nullprivate lateinit var btnMsg: Buttonoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)btnMsg = findViewById(R.id.btn_msg)//绑定servicebindService(Intent(this, MessengerService::class.java),connection, Context.BIND_AUTO_CREATE)btnMsg.setOnClickListener {mService?.let {//创建消息,通过Bundle传递数据var message = Message.obtain(null, 100)message.data = Bundle().apply {putString("data", "服务端,我给你发送消息了")}//将客户端的Messenger对象传递给服务端,才能让双方互相通信message.replyTo = mClientMessenger//像服务端进程发送消息it.send(message)}}}/*** 客户端Messenger对象*/private val mClientMessenger: Messenger = Messenger(MessengerHandler())/*** 用于构建客户端的Messenger对象,并处理服务端的消息*/private class MessengerHandler : Handler() {override fun handleMessage(msg: Message) {when (msg.what) {100 -> {println(msg.data.getString("data"))}}}}private val connection: ServiceConnection = object: ServiceConnection {override fun onServiceConnected(name: ComponentName?, ibinder: IBinder?) {mService = Messenger(ibinder)}override fun onServiceDisconnected(name: ComponentName?) {}}override fun onDestroy() {//解绑serviceunbindService(connection)super.onDestroy()}
}

AIDL

        AIDL底层也是通过Binder实现的。
        Messenger 是以串行的方式处理客户端发来的消息,如果大量消息同时发送到服务端,服务端只能一个一个处理,所以大量并发请求就不适合用 Messenger ,而且Messenger 只适合传递消息,不能跨进程调用服务端的方法。AIDL 可以解决并发和跨进程调用方法的问题

支持数据类型:

  • 八种基本数据类型:byte、char、short、int、long、float、double、boolean
  • String,CharSequence
  • 实现了Parcelable接口的数据类型
  • List 类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
  • Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象

aidl跨进程通信的步骤:

  1. 创建aidl文件
  2. build后生成aidl对应的java文件
  3. 创建服务端Service
  4. 创建客户端Activity,bindService(),获取IBinder的proxy 

Socket

        Socket也称作“套接字“,是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用以实现进程在网络中通信。
分为流式套接字和数据包套接字,分别对应网络传输控制层的TCP和UDP协议

http://www.lryc.cn/news/320830.html

相关文章:

  • day03vue学习
  • 32. 最长有效括号
  • 如何在 docker 容器内部运行 docker命令
  • Poly Kernel Inception Network在遥感检测中的应用
  • tiktok 与 赵长鹏 遭遇了什么
  • Lua中文语言编程源码-第七节,更改lstrlib.c 标准字符串操作与模式匹配库函数, 使Lua加载中文库关键词(标准字符串操作与模式匹配库相关)
  • EtherCAT开源主站 IGH 介绍及主站伺服控制过程
  • 自然语言:python实现自然语言处理中计算文件中的英语字母的熵
  • 分类预测 | Matlab实现BiTCN双向时间卷积神经网络数据分类预测/故障识别
  • 基于SpringBoot的后勤管理系统【附源码】
  • 智能仓储系统|基于JSP技术+ Mysql+Java+ Tomcat的智能仓储系统设计与实现(可运行源码+数据库+设计文档)
  • Layui实现删除及修改后停留在当前页
  • 小型研发型企业,如何筛选合适的内外网数据交换方案?
  • Visual Studio 常用快捷键
  • 【WEEK3】 【DAY4】JSON Interaction Handling Part Three【English Version】
  • 蓝桥杯物联网竞赛_STM32L071_12_按键中断与串口中断
  • Java安全 反序列化(1) URLDNS链原理分析
  • 电脑插上网线之后仍然没网络怎么办?
  • easyexcel读和写excel
  • 路由器级联
  • CentOS7使用Docker部署.net Webapi
  • Windows程序员用MAC:初始设置(用起来像win一些)
  • 基于深度学习YOLOv8+Pyqt5的工地安全帽头盔佩戴检测识别系统(源码+跑通说明文件)
  • csv编辑器是干什么的?
  • 计算机网络——物理层(奈氏准则和香农定理)
  • XML语言的学习记录3-解析
  • 【Linux】cat vim 命令存在着什么区别?
  • MeterSphere和Jmeter使用总结
  • 学习笔记Day8:GEO数据挖掘-基因表达芯片
  • 如何将大华dav视频转mp4?一键无损清晰转换~