Android MemoryFile 共享内存

应用场景:

跨进程传输大数据,如文件、图片等;

技术选型:

共享内存–MemoryFile;

优点:

1. 共享内存没有传输大小限制,所以和应用总的分配内存一样(512MB);
2. MemoryFile 是对 SharedMemory 的包装,使用简单便于管理;

实现步骤:

(以A进程共享文件a.txt给B进程为例)

A进程: 创建共享内存空间工具类
 
public class ShareMemoryUtils {private static ParcelFileDescriptor getPfdFromMemoryFile(final String name, final byte[] bytes) {ParcelFileDescriptor pfd = null;try {long startTime = System.currentTimeMillis();MemoryFile memoryFile = null;try {memoryFile = new MemoryFile(name, bytes.length);memoryFile.allowPurging(true);memoryFile.writeBytes(bytes, 0, 0, bytes.length);pfd = getParcelFileDescriptor(memoryFile);} catch (Exception e) {e.printStackTrace();} finally {closeMemoryFile(memoryFile, null);}}});}return pfd;}private static ParcelFileDescriptor getParcelFileDescriptor(MemoryFile memoryFile) {try {Method method = MemoryFile.class.getDeclaredMethod("getFileDescriptor");method.setAccessible(true);FileDescriptor fd = (FileDescriptor) method.invoke(memoryFile);return ParcelFileDescriptor.dup(fd);} catch (Exception e) {e.printStackTrace();return null;}}private static void closeMemoryFile(MemoryFile memoryFile, ParcelFileDescriptor pfd) {if (pfd != null) {try {pfd.close();} catch (IOException e) {e.printStackTrace();}}if (memoryFile != null) {memoryFile.close();}}}
A进程:创建aidl接口,使用binder接口传递文件描述符
interface IMemoryFileApi {ParcelFileDescriptor getParcelFileDescriptor(String type, String params);boolean setParcelFileDescriptor(String type, in ParcelFileDescriptor pfd, String params);oneway void releaseParcelFileDescriptor(String type);
}
B进程:通过bindService连接到A进程,并调用aidl接口获取文件描述符
/*** 通过 binder 接口获取远程进程共享内存的文件描述符*/private ParcelFileDescriptor getParcelFileDescriptor() {try {if (iMemoryFileApi != null) {ParcelFileDescriptor pfd = iMemoryFileApi.getParcelFileDescriptor();return pfd;}} catch (Exception e) {e.printStackTrace();}return null;}
B进程:通过文件描述符读取数据流即可;

注意:

文件描述符在每个进程都有副本,A进程的文件描述符被B进程接收后,实际上已经有了两份文件描述符,即两个进程有各自的内存映射空间。所以B进程读取数据流之后,除了要关闭自己进程的文件描述符对象之外,还要调用接口关闭A进程中的文件描述符;
B进程想要把修改后的文件数据回写给A进程时,需要做的操作和A进程的操作是完全一样的,把文件数据重新创建共享内存,再把文件描述符通过binder接口传递给A进程即可;

总结

网上很多时间比较久的贴子,通过各种反射在A进程获取MemoryFIle来读取共享数据,这种方式并不可取;MemoryFile新版本的封装方式就体现了它的使用方式,Google是希望随时使用随时创建MemoryFile并把文件描述附共享出去这种方式来实现功能的。


android MemoryFile内存共享

进程之间传递数据,由于Binder传递数据有限制1M,所以如果遇到大的数据传递的时候就需要使用使用到MemoryFile内存共享来解决,最合适不过了

首先,MemoryFile是基于Binder自带的transact方法进行传输数据的,因此直接继承Binder即可,不过一般项目中免不了传递一些基本数据类型或者bean数据,因此一般结合aidl一起使用。

android aidl使用记录

  • 服务端处理数据
private byte[] buffer = new byte[1024];//public class MyBinder extends IRtcService.Stub {public class MyBinder extends Binder {//此方法Binder自带@Overridepublic boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {LogUtil.e("接收到远端调用" + "code" + code);if (code == 100) {try {ParcelFileDescriptor pfd = data.readParcelable(null);// 或者
//                    ParcelFileDescriptor pfd = data.readFileDescriptor();FileDescriptor fileDescriptor = pfd.getFileDescriptor();FileInputStream fi = new FileInputStream(fileDescriptor);fi.read(buffer);fi.close();LogUtil.e("--->" + new String(buffer).replace("\0", ""));//返回给客户端reply.writeString("服务器接受数据成功");reply.writeInt(200);return true;} catch (IOException e) {e.printStackTrace();}}return super.onTransact(code, data, reply, flags);}}
  • 客户端
private ServiceConnection mConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {try {/****/// 参数1文件名,可为null,参数2文件长度mMemoryFile = new MemoryFile(null, 1024);//在设置了allowPurging为false之后,这个MemoryFile对应的Ashmem就会被标记成"pin",// 那么即使在android系统内存不足的时候,也不会对这段内存进行回收mMemoryFile.allowPurging(false);android.os.Parcel data = android.os.Parcel.obtain();android.os.Parcel reply = android.os.Parcel.obtain();byte[] buffer = "31283216382163812362183621832163812".getBytes();mMemoryFile.writeBytes(buffer, 0, 0, buffer.length);Method getFileDescriptorMethod = mMemoryFile.getClass().getDeclaredMethod("getFileDescriptor");if (getFileDescriptorMethod != null) {FileDescriptor fileDescriptor = (FileDescriptor) getFileDescriptorMethod.invoke(mMemoryFile);// 序列化,才可传送ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(fileDescriptor);//写入数据,对应服务端用data.readParcelable(null)接收数据data.writeParcelable(pfd, 0);// 或者,对应服务端用data.readFileDescriptor()接收数据
//                    data.writeFileDescriptor(fileDescriptor);/*** code 是一个整形的唯一标识,用于区分执行哪个方法,客户端会传递此参数,告诉服务端执行哪个方法;* data客户端传递过来的参数;* replay服务器返回回去的值;* flags标明是否有返回值,0为有(双向),1为没有(单向)。*/service.transact(100, data, reply, 0);//服务器返回的值String message = reply.readString();LogUtil.e("--message--->" + message);int code = reply.readInt();LogUtil.e("--code--->" + code);if (code==200){data.recycle();reply.recycle();mMemoryFile.close();mMemoryFile=null;}}} catch (RemoteException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName name) {if (mConnection != null) {try {iRtcService = null;unbindService(mConnection);} catch (Exception e) {}}}};
  • 结果

    客户端

03-15 21:16:36.011 4327-4327/com.fuyao.elf_android_remote E/elf_remote: --message--->服务器接受数据成功
03-15 21:16:36.011 4327-4327/com.fuyao.elf_android_remote E/elf_remote: --code--->200

 服务端

03-15 21:16:36.010 4300-4313/com.fuyao.elf_android_center:rtc_remote E/elf_center: 接收到远端调用code100
03-15 21:16:36.010 4300-4313/com.fuyao.elf_android_center:rtc_remote E/elf_center: --->31283216382163812362183621832163812

Android内存映射文件实现

1. 什么是内存映射文件

内存映射文件是一种将磁盘上的文件映射到内存中的方法。通过内存映射文件,可以将文件的内容直接映射到内存中的一个地址空间,从而可以直接对内存进行读写操作,而无需通过传统的文件IO操作。

在Android开发中,内存映射文件常常用于处理大文件或者需要频繁读写的文件,因为通过内存映射文件可以获得更高的IO性能。

2. Android内存映射文件的实现方式

Android提供了MemoryFile类来实现内存映射文件的功能。MemoryFile是一个基于共享内存的IPC(进程间通信)机制,它允许一个进程将一个内存映射文件映射到另一个进程的地址空间中。

下面是一个简单的代码示例,演示了如何使用MemoryFile实现内存映射文件:

// 创建一个内存映射文件
MemoryFile memoryFile = new MemoryFile("test", 1024);// 向内存映射文件写入数据
String data = "Hello, MemoryFile!";
byte[] buffer = data.getBytes();
memoryFile.writeBytes(buffer, 0, 0, buffer.length);// 从内存映射文件读取数据
byte[] readBuffer = new byte[buffer.length];
memoryFile.readBytes(readBuffer, 0, 0, readBuffer.length);
String readData = new String(readBuffer);// 打印读取的数据
System.out.println(readData);// 释放内存映射文件
memoryFile.close();


在上面的代码中,首先我们创建了一个大小为1024字节的内存映射文件。然后,我们向内存映射文件写入了字符串数据,接着又从内存映射文件中读取了数据,并将其转换为字符串。最后,我们释放了内存映射文件。

需要注意的是,MemoryFile类只能在同一个进程的不同线程之间进行通信,如果需要在不同进程之间通信,则需要使用其他的IPC机制,比如Binder。

3. 内存映射文件的优势和应用场景


内存映射文件相比于传统的文件IO操作有如下优势:

  • 更高的IO性能:由于内存映射文件将文件内容映射到内存中,所以可以避免频繁的磁盘IO操作,从而获得更高的IO性能。
  • 更低的内存占用:内存映射文件只将文件的部分或全部内容映射到内存中,而不是将整个文件加载到内存中,所以可以减少内存的占用。
  • 更方便的数据访问:通过内存映射文件,可以直接对内存中的数据进行读写操作,而无需通过文件IO相关的API,从而简化了数据访问的操作。

内存映射文件常常应用于以下场景:

  • 大文件处理:当需要处理大文件时,通过内存映射文件可以获得更高的IO性能。
  • 频繁读写文件:当需要频繁读写文件时,通过内存映射文件可以避免频繁的磁盘IO操作,提高程序的响应速度。
  • 进程间通信:通过内存映射文件可以在同一个进程的不同线程之间进行通信。

4. 总结

本文介绍了Android内存映射文件的实现方式以及其优势和应用场景。通过内存映射文件,我们可以获得更高的IO性能和更方便的数据访问方式。在处理大文件或者需要频繁读写文件的场景下,使用内存映射文件可以提高程序的性能和响应速度。
 

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

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

相关文章

Java 根据文件名获取文件类型

比如文件名是“测试文件.png”,则获取的文件类型就是 png 直接上一个通用的方法,拿去直接就能用。 // 比如入参文件名是“测试文件.png”,则出参就是 pngprivate String getFileSuffix(String fileName) {String[] fileStr fileName.split(&…

educoder中共享单车之数据可视化

第1关:绘制地图 <%@ page language="java" contentType="text/html; charset=utf-8"pageEncoding="utf-8"%> <html> <head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /&…

专用设备上的SD卡插入电脑想读取数据,提示要格式化?

环境&#xff1a; Win10 专业版 车载感应数据专用SD卡 问题描述&#xff1a; 专用设备上的SD&#xff0c;现在把SD卡从设备取出&#xff0c;用读卡器插入电脑提示要格式化&#xff1f; 解决方案&#xff1a; 1.先进入PE查看SD分区情况&#xff0c;SD格式为ext4 查看文件…

lombok中使用@Builder构造器模式时的默认值问题

这里写自定义目录标题 问题case原因解决方案 文章参考来源&#xff1a;https://chenyongjun.vip/articles/107 问题case Lombok 使用广泛&#xff0c;这里分享一个 Lombok Builder 小 case&#xff0c;今天自己踩了坑。 Data Builder public class User {private String name…

MLP 有哪些可学习的参数

多层感知机&#xff08;MLP&#xff09;的参数是需要在训练过程中学习的。MLP是一种前馈神经网络&#xff0c;其结构包括输入层、多个隐藏层和输出层。在训练过程中&#xff0c;MLP通过反向传播算法来调整网络的权重&#xff0c;以最小化预测值与实际值之间的误差。 MLP的学习…

安卓开发——Android Studio常见报错与解决方法

1. No toolchains found in the NDK toolchains folder for ABI with prefix: arm-linux-android 这个错误是由于较新版本的NDK的./toolchains目录中没有arm-linux-androideabi文件&#xff0c;解决办法是从旧的NDK版本里面复制到自己的NDK的版本里面&#xff0c;就可以了。 打…

WSL登录时提示nsenter: cannot open /proc/320/ns/time: No such file or directory的解决办法

在登录 WSL 的 Ubuntu 时&#xff0c;不仅要求 root 权限&#xff0c;还登录失败&#xff0c;提示“nsenter: cannot open /proc/320/ns/time: No such file or directory”。 解决办法是在 powershell 中执行 “wsl – sudo vi /etc/profile”命令&#xff0c;删除文件内容&a…

JavaWeb——感谢尚硅谷官方文档

JavaWeb——感谢尚硅谷官方文档 XML一、xml简介二、xml的语法1、文档申明2、xml注释3、xml元素4、xml属性5、xml语法规则 三、xml解析技术1、使用dom4j解析xml Tomcat一、JavaWeb的概念二、web资源的分类三、常见的web服务器四、Tomcat的使用1、安装2、Tomcat的目录介绍3 启动T…

初识Java 18-3 泛型

目录 边界 通配符 编译器的能力范畴 逆变性 无界通配符 捕获转换 本笔记参考自&#xff1a; 《On Java 中文版》 边界 在泛型中&#xff0c;边界的作用是&#xff1a;在参数类型上增加限制。这么做可以强制执行应用泛型的类型规则&#xff0c;但还有一个更重要的潜在效果…

如何在AD的PCB板做矩形槽孔以及如何倒圆弧角

Altium Designer 22下载安装教程-CSDN博客 如何在AD上创建完整的项目-CSDN博客 开始前&#xff0c;请先安装后AD&#xff0c;并创建好项目。 目录 1. 如何在AD的PCB板做矩形槽孔 2. 如何在AD的PCB板倒圆弧角 1. 如何在AD的PCB板做矩形槽孔 首先&#xff0c;我们进入上面创…

PTA 7-9 堆栈操作合法性

7-9 堆栈操作合法性 分数 20 全屏浏览题目 作者 DS课程组 单位 浙江大学 假设以S和X分别表示入栈和出栈操作。如果根据一个仅由S和X构成的序列&#xff0c;对一个空堆栈进行操作&#xff0c;相应操作均可行&#xff08;如没有出现删除时栈空&#xff09;且最后状态也是栈空…

2023年11个最佳免费WordPress主题

如果您刚刚开始使用 WordPress&#xff0c;您可能会很自然地认为&#xff0c;只要免费的WordPress主题看起来像您想要的网站主题&#xff0c;那么它就很合适。不幸的是&#xff0c;事情并没有那么简单。这就是为什么在今天的文章中&#xff0c;我们概述了一份可靠的标准清单&am…

某基金公司赵哥“逆袭”了!!!

赵哥&#xff0c;在上海一家基金公司做运维主管。 平时工作的首要任务&#xff0c;就是保障公司各项信息系统的安全运行。 万一系统运行中出现了一些重要问题&#xff0c;他还要负责进行调查、记录与汇报... 总之&#xff0c;责任很重&#xff0c;该说不说&#xff0c;搞不好…

Java互联网+公立医院绩效考核源码

一、建设信息化医院绩效考核的意义 1.提高考核效率&#xff1a;通过信息化手段&#xff0c;可以将绩效考核数据自动采集、整理、分析和报告&#xff0c;大大提高了考核效率&#xff0c;减少了人工干预和错误率。 2.增强考核公正性&#xff1a;信息化考核可以减少人为因素的干…

Electronica上海 Samtec 验证演示 | FireFly™Micro Flyover System™

摘要/前言 在圆满结束的2023慕尼黑上海电子展上&#xff0c;Samtec虎家团队为观众带来了前所未有的丰富体验&#xff1a;产品展示、采访、Demo演示、抽奖互动~ 尤其是Demo演示&#xff0c;虎家工程师FAE Marcus为大家带来了数个精彩的产品与系统讲解演示。其中更不乏合作伙伴…

Windows、VMware问题集合

Windows、VMware问题集合 一. Windows11安装VMware17提升虚拟机性能1. 桌面右击图标点击属性——>兼容性&#xff0c;找到“以管理员身份运行此程序”勾选&#xff0c;最后点击确定即可。2. 关闭win11的内核隔离功能。 二. VMware虚拟机报错&#xff08;虚拟化性能计数器需要…

C语言——求分段函数 y=f(x)的值

求分段函数 yf(x)的值,f(x)的表达式如下: #define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int x,y;printf("请输入x的值&#xff1a;");scanf("%d",&x);if(x>5){yx3;}else if(x>0 && x<5){y0;}elsey2*x30;pr…

Python 基础【四】--数据类型-字符串【2023.11.23】

1 .定义 字符串是 Python 的一种数据类型&#xff0c;它可以通过单引号 ‘、双引号 "、三引号 ‘’’ 或 “”"来定义。 aabcd bacsdcd c"""accsfv""" print(a) print(b) print(c)2 .基本操作 访问单个字符 注意&#xff1a;从0开始…

Java_注解

1. 简介 在Java中&#xff0c;注解&#xff08;Annotation&#xff09;是一种元数据形式&#xff0c;它为代码添加了额外的信息&#xff0c;这些信息可以被编译器、工具、框架或运行时环境使用。注解提供了一种声明性的方式来向程序中添加元数据&#xff0c;而不需要修改程序的…

Harmony Ble蓝牙App(二)连接与发现服务

Ble蓝牙App&#xff08;二&#xff09;连接与发现服务 前言正文一、BlePeripheral回调二、连接和断连三、连接状态回调四、发现服务五、服务提供者六、显示服务七、源码 前言 在上一篇中我们进行扫描设备的处理&#xff0c;本文中进行连接和发现服务的数据处理&#xff0c;运行…