Android 实现多进程通讯(如何实现多进程开发,Binder、AIDL)

news/2024/9/11 2:57:14/ 标签: android, binder

目录


1)为什么App需要多进程

2)什么是多进程开发?

3)如何实现多进程开发?

4)跨进程间通讯(案例)

5)多进程需要注意什么问题?

6)多进程的底层原理是什么?【待写】



一、为什么App需要多进程?


某些应用场景下,单个进程可能无法满足需求,通过将任务分配到不同的进程中并行处理,可以提高系统整体的性能和响应速度。

在Android中,虚拟机分配给各个进程的运行内存是有限制值的,多进程app可以在系统中申请多份内存

通过创建独立的后台进程,可以确保应用在主进程被杀死或处于台时仍然能够执行一些必要的任务,如推送、消息接收等。

很多app都已经开始使用多进程,比如:推送,保活,插件化,内存不够用,webview,闹钟,电话等等。

在这里插入图片描述

二、什么是多进程开发?


多进程是指一个应用程序可以同时运行在多个独立的进程中。每个进程都有自己独立的虚拟机实例和资源管理器,并且它们之间相互隔离。一个应用可以有多个进程,就有多个dalivk虚拟机,对应多个内存空间。

默认情况下,Android应用程序在同一个进程中运行,即单进程模式。这意味着应用程序的所有组件(Activity、Service、BroadcastReceiver等)都在同一个进程中执行。但是,通过配置AndroidManifest.xml文件中的android:process属性,开发者可以为特定的组件或整个应用程序指定不同的进程名称,从而实现多进程开发。

三、如何实现多进程开发以及通讯?


默认情况下,启动一个APP,仅仅启动了一个进程,该进程名为包名,那如何定义多进程呢? Android 提供了一种方式,就是在 AndroidManifest 文件中可以通过 “android:process” 来指定进程:

  1. 不指定 process: 默认的进程,进程名为包名
  2. 指定 process,但以":"开头: 该进程为当前APP的私有进程,不允许其他APP访问
  3. 指定 process,但以小写字母开头的字符串: 该进程为全局进程 ,其他应用可设置相同的shareUID来共享该进程

场景

当应用的一部分需要高安全性或高稳定性时,比如支付模块或敏感数据处理模块。这里我将给出一个简化的案例:一个包含普通功能和支付功能的应用,我们将支付功能放在单独的进程中以提高安全性。

步骤一:定义支付进程的Service

<service  android:name=".PaymentService"  android:process=":payment"  android:exported="false" />

步骤二:创建PaymentService

public class PaymentService extends Service {  @Override  public int onStartCommand(Intent intent, int flags, int startId) {  // 接收来自其他组件的数据  String orderId = intent.getStringExtra("orderId");  // 模拟支付逻辑  boolean isSuccess = performPayment(orderId);  // 通知结果(实际开发中可能需要通过广播、AIDL等方式)  // 这里为了简化,我们假设有某种方式通知UI层  return START_NOT_STICKY;  }  private boolean performPayment(String orderId) {  // 这里实现具体的支付逻辑  // 例如调用第三方支付SDK等  return true; // 假设支付成功  }  @Override  public IBinder onBind(Intent intent) {  // 如果需要,可以返回IBinder实现IPC  return null;  }  
}

步骤三:从主进程启动PaymentService

Intent intent = new Intent(this, PaymentService.class);  
intent.putExtra("orderId", "123456789");  
startService(intent);

如果支付服务需要返回结果给主进程,或者主进程需要向支付服务发送指令,下面我们需要学习一下跨进程通信(IPC)

四、跨进程间通讯


Android中支持的多进程通信方式主要有以下几种,它们之间各有优缺点,可根据使用场景选择选择:
1)BroadcastReceiver:即广播,但只能单向通信,接收者只能被动的接收消息。
2)Binder:是Android系统内部使用的一种高效IPC机制,基于C/S架构,通过内存映射实现高效的进程间通信。高效性,数据传输速度快。支持复杂的数据类型传递
3)ContentProvider:是Android系统中一种轻量级的跨进程通信方式,主要用于在不同应用程序之间共享数据。
4)AIDL:是Android系统中用于定义跨进程通信接口的一种语言,它允许定义可在不同进程间共享的服务接口。

这里我们主要介绍Binder。

4.1 Binder


优点

解决安全问题,内存不够的问题。
1)比如加载图片的时候,出现崩溃,导致安全问题出现。如果用子线程进行加载,那么即使崩溃了也不影响主线程。在比如微信小程序就是另外进程,不能影响微信。
2)为什么手机运行内存8G,16G,加载一张大图就会导致内存不够用呢?难道他有几G那么大?并不是,因为每个app运行,根据手机的不同,进程可以分到几十兆,或者几百兆的内存空间(如下图)。所以多个进程,那么内存就多了。
在这里插入图片描述

内存划分

进程之间的内存是相互隔离的。
在这里插入图片描述
那么如何才能实现进程之间相互通讯?
Android 为什么要增加Binder?

在这里插入图片描述
传统的方式,需要进行两次拷贝。
在这里插入图片描述Binder拷贝:
在这里插入图片描述
内存映射到底是啥?虚拟地址映射到物理地址,而MMAP,就是将用户空间映射到内存空间。不需要拷贝了。通过快捷方式进行举例。

4.2 AIDL


是什么?简化调用Binder的流程。因为Binder的规则还是比较复杂的,而AIDL可以直接生成这套规则。这就是他的作用。

接下来我们就使用AIDL实现进程间通讯。比如说,两个进程,A进程通过发送一个字符串,B进程收到后进行对应的逻辑处理。

(1)打开aidl,不打开,生成不了aidl文件

先在build.gradle文件里面添加一个
android {...    buildFeatures.aidl = true...
}

(2)步骤 1: 定义AIDL接口

创建一个AIDL文件夹
在这里插入图片描述
创建AIDL文件
在这里插入图片描述

// IMessageService.aidl
package com.example.myapplicationa;// Declare any non-default types here with import statementsinterface IMessageService {/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/String sendMessage(String message);
}

(3)步骤 2: 实现AIDL接口

在这里插入图片描述

package com.example.myapplicationaimport android.app.Service
import android.content.Intent
import android.os.IBinder
import android.util.Log
import java.util.Localeclass MessageService : Service() {private val mBinder: IMessageService.Stub = object : IMessageService.Stub() {override fun sendMessage(message: String): String {// 这里可以添加一些处理逻辑,比如转换大小写等Log.d("AIDL A", "收到 sendMessage: ")return "Processed: " + message.uppercase(Locale.getDefault())}}override fun onBind(intent: Intent): IBinder? {return mBinder}
}

在AndroidManifest.xml中声明这个Service,并指定它运行在多进程中:

  <serviceandroid:name=".MessageService"android:exported="true"android:process=":remote"><intent-filter><action android:name="com.example.myapplicationa.IMessageService" /></intent-filter></service>

(4)步骤 3: 在App B中绑定Service

将IMessageService.aidl文件复制到App B的src/main/java/com/example/myapplicationa目录下。
在这里插入图片描述
在App B中创建一个ServiceConnection来绑定到App A的Service:

package com.example.myapplicationbimport android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.os.RemoteException
import android.util.Log
import androidx.activity.ComponentActivity
import com.example.myapplicationa.IMessageServiceclass MainActivity : ComponentActivity() {private var mMessageService: IMessageService? = nullprivate var mIsBound = falseoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)}private val mConnection: ServiceConnection = object : ServiceConnection {override fun onServiceConnected(className: ComponentName, service: IBinder) {mMessageService = IMessageService.Stub.asInterface(service)try {val response = mMessageService!!.sendMessage("Hello from App B")// 处理响应Log.d("AIDL B", "Received response: $response")} catch (e: RemoteException) {e.printStackTrace()}mIsBound = true}override fun onServiceDisconnected(arg0: ComponentName) {mMessageService = nullmIsBound = false}}override fun onStart() {super.onStart()val intent = Intent()intent.setComponent(ComponentName("com.example.myapplicationa", "com.example.myapplicationa.MessageService"))bindService(intent, mConnection, BIND_AUTO_CREATE)}override fun onStop() {super.onStop()if (mIsBound) {unbindService(mConnection)mIsBound = false}}
}

运行程序,如果收到这个log,就说明成功了。

在这里插入图片描述

好了,以上就是AIDL的简单使用。

五、多进程需要注意什么问题?


1、静态成员和单例模式完全失效 。Android 为每一个进程分配一个独立的虚拟机,不同虚拟机在内存分配上有不同地址空间,这就导致多进程下访问同一个类的对象会产生多分副本。所以在一个进程中修改某个值,只会在当前进程有效,对其他进程不会造成任何影响。

2、线程同步机制完全失效。因为多进程的内存地址空间不同,锁的不是同一个对象,所以不管是锁对象还是锁全局对象都无法保证线程同步。

3、SharedPreferences 的可靠性下降。因为SharedPreferences 底层通过读写XML实现,并发读写显然是不安全的操作,甚至会出现数据错乱。

4、Application 会多次创建。

5.1 Application 会多次创建 的解决方法


在Application的onCreate中获取进程Id来判断不同进程,然后做不同的事情。

public class MyApplication extends BaseApplication {public static MyApplication instances;@Overridepublic void onCreate() {super.onCreate();instances = this;if (isAppMainProcess()) {.....}.....}
}public static boolean isAppMainProcess() {try {int pid = android.os.Process.myPid();String process = getAppNameByPID(instances, pid);if (TextUtils.isEmpty(process)) {return true;} else if ("com.xxx.xxx".equalsIgnoreCase(process)) {return true;} else {return false;}} catch (Exception e) {e.printStackTrace();return true;}}

http://www.ppmy.cn/news/1507542.html

相关文章

Armv9.5架构新增的关键扩展--精简版

Armv9.5架构扩展是对Armv9.4的扩展。它增加了强制性和可选的架构特性。有些特性必须一起实现。实现是符合Armv9.5规范,需要满足以下条件: 符合/兼容Armv9.4规范包含所有Armv9.5架构的强制性特性。符合Armv9.5规范的实现还可以包括: Armv9.5的可选特性以下是arm9.5架构中关键…

1、Unity【基础】3D数学

3D数学 文章目录 3D数学1、数学计算公共类Mathf1、Mathf和Math2、区别3、Mathf中的常用方法&#xff08;一般计算一次&#xff09;4、Mathf中的常用方法&#xff08;一般不停计算&#xff09;练习 A物体跟随B物体移动 2、三角函数1、角度和弧度2、三角函数3、反三角函数练习 物…

NAT、服务代理、内网穿透

文章目录 NAT技术NAT IP转换过程NATPNAT的优点NAT的缺点 代理服务器正向代理反向代理 内网穿透和内网打洞内网穿透内网打洞 NAT技术 NAT技术即网络地址转换技术。用于将私有IP地址转换为公共IP地址&#xff0c;以便在互联网或其他外部网络中通信。为了解决IPv4协议下IP地址不足…

keepalived-单播模式设定

目录 配置准备 配置过程 测试结果 配置准备 两个虚拟机&#xff0c;都要有keepalived&#xff0c;vip为172.25.254.100 配置过程 [rootka1 ~]# vim /etc/keepalived/keepalived.conf [rootka1 ~]# systemctl restart keepalived.service unicast_src_ip 172.25.254.10uni…

【Datawhaler AI夏令营-浪潮】大模型应用开发学习记录

大模型应用开发 简要&#xff1a;Datawhale 2024 年 AI 夏令营 第四期联合浪潮信息一同开展的学习活动。 个人大模型训练学习还是需要一些成本的&#xff0c;暂时没钱升级显卡&#xff0c;主打哪里能白嫖去哪嫖卡。 大模型应用开发活动安排是&#xff1a; 大模型部署大模型…

【Kettle】kettle连接MySQL数据库连接不上解决方案汇总

前言 近期项目上经常用到ETL&#xff08;数据抽取转换加载&#xff09;&#xff0c;就想到了之前用过的kettle工具&#xff0c;下班回家想着再玩玩这个工具吧&#xff0c;结果在连接MySQL时&#xff0c;遇到了各种问题&#xff0c;就顺手整理记录一下。所以今天晚上的主题是&a…

使用Python下载飞书共享表格数据教程

写在前面 随着企业协作办公软件的流行&#xff0c;飞书以其高效的协作能力和便捷的共享功能&#xff0c;成为了许多公司必备的工具之一。在日常工作中&#xff0c;我们经常需要从飞书中下载共享的表格数据进行分析。本文将详细介绍如何使用Python下载飞书共享表格数据。 前置…

element plus el-select修改后缀图标

使用 element plus 提供的api 默认为&#xff1a; 修改后为&#xff1a; 方法&#xff1a; <el-select v-model"value" placeholder"Select" size"large" style"width: 120px;":teleported"false" :suffix-icon"…

LVS多模式集群攻略!

目录 NAT模式下的lvs集群准备工作具体步骤客户机lvs服务器1服务器2 测试 DR模式下的lvs集群具体流程客户机&#xff1a;路由器LVS服务器1服务器2测试 防火墙标签解决轮询问题LVS持久链接解决方案 NAT模式下的lvs集群 lvs-nat概念&#xff1a;修改请求报文的目标IP,多目标IP的D…

ASC格式的协议数据解析

函数来自RTT的AT组件 - at_client.c RTT-AT命令 例如&#xff0c;数据是 CGREG: 0,1&#xff0c;通过at_resp_parse_line_args_by_kw把1赋予link_stat。 at_resp_parse_line_args_by_kw at_resp_parse_line_args at_resp_parse_line_args(resp, 1,"IP%s", ip); …

pythonUI自动化007::pytest的组成以及运行

pytest组成&#xff1a; 测试模块&#xff1a;以“test”开头或结尾的py文件 测试用例&#xff1a;在测试模块里或测试类里&#xff0c;名称符合test_xxx函数或者示例函数。 测试类&#xff1a;测试模块里面命名符合Test_xxx的类 函数级&#xff1a; import pytestclass Test…

深度学习 —— 个人学习笔记14(ResNet、DenseNet)

声明 本文章为个人学习使用&#xff0c;版面观感若有不适请谅解&#xff0c;文中知识仅代表个人观点&#xff0c;若出现错误&#xff0c;欢迎各位批评指正。 二十八、残差网络&#xff08; ResNet &#xff09; import torch import torchvision import time from torch impo…

白骑士的Matlab教学进阶篇 2.5 Simulink

系列目录 上一篇&#xff1a;白骑士的Matlab教学进阶篇 2.4 图像处理 Simulink是MATLAB的扩展工具&#xff0c;提供了一个图形化的建模和仿真环境。它广泛应用于系统设计、仿真、自动控制、信号处理等领域。本文将详细介绍Simulink的简介与基本使用、建立与仿真模型、控制系统…

Linux网络:I/O多路转接poll

目录 一、poll函数解析 二、events和revents事件取值 三、poll的优点 四、poll的缺点 一、poll函数解析 poll函数接口&#xff1a; #include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout); 参数解析&#xff1a; // struct pollfd 结构 struct p…

【C总集篇】第三章 字符串和格式化输入/ 输出

文章目录 第三章 字符串和格式化输入/ 输出字符/字符串简要理解前言字符介绍和使用数组的简单介绍数组的创建格式 字符串介绍和使用printf函数printf函数一般格式printf()的转换说明修饰符printf函数部分格式字符常用格式字符详解%d%f%c%s printf的返回值 scanf规则说明转化说明…

Spring Boot 3 新特性

Spring Boot 3 带来了许多新特性和改进&#xff0c;这些特性主要围绕提升性能、简化配置、增强的安全性以及支持更现代的Java和库版本。以下是一些Spring Boot 3的关键特性&#xff1a; 支持Java 17和更高版本&#xff1a; Spring Boot 3 官方支持Java 17&#xff0c;并且由于J…

VM——深度学习算子GPU版本耗时不稳定

1、问题&#xff1a;使用3080TI显卡4台130万相机&#xff0c;GPU版本算子&#xff0c;耗时不稳定&#xff0c;15ms-150ms波动 2、方法&#xff1a; 1&#xff09;参考海康提供的问题手册

数学中常用的解题方法

文章目录 待定系数法应用示例1. 多项式除法2. 分式化简3. 数列通项公式 总结 递归数列特征方程特征根的求解通项公式的求解示例 错位相减&#xff0c;差分错位相减法差分的应用结合理解 韦达定理二项式定理二项式定理的通项公式二项式系数的性质应用示例 一元二次求解1. 因式分…

怎样才算精通 Excel?

最强AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频百万播放量https://aitools.jurilu.com/ 高赞回答很系统&#xff0c;但普通人这么学&#xff0c;没等精通先学废了&#xff01; 4年前&#xff0c;我为了学数据分析&#…

Cycript安装报错 Library not loaded终极解决方案

一、下载安装 Cycript 官方完整 资源下载完成后&#xff0c;解压。目录如下&#xff1a; 二、执行 打开命令终端,cd到对应目录&#xff0c;然后执行./cycript #第一步&#xff1a;cd到解压的目录 cd /xx/cycrpt_0#执行&#xff1a; ./cycript 2.1、报错Library not Loaded …