专业长沙做网站公司,做公众号关注网站,手机微信网站模板,地铁网站建设特点应用场景#xff1a;
跨进程传输大数据#xff0c;如文件、图片等#xff1b;
技术选型#xff1a;
共享内存–MemoryFile#xff1b;
优点#xff1a;
1. 共享内存没有传输大小限制#xff0c;所以和应用总的分配内存一样#xff08;512MB#xff09;#xff1…应用场景
跨进程传输大数据如文件、图片等
技术选型
共享内存–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 (code200){data.recycle();reply.recycle();mMemoryFile.close();mMemoryFilenull;}}} 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: ---31283216382163812362183621832163812Android内存映射文件实现
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性能和更方便的数据访问方式。在处理大文件或者需要频繁读写文件的场景下使用内存映射文件可以提高程序的性能和响应速度。