赞
踩
Android 提供了几种进程间通信的方式,除了Socket,基本都是基于binder实现的。为什么要用共享内存来实现呢?因为binder传输数据被限制在1M-8k,在较大的数据交换一般会使用文件,但效率非常的低,因此使用共享内存是很好的方式。在内存中开辟一块空间,通过binder或者其他方式将fd(文件描述符)传递到客户端或服务端进程,从而实现大文件传输。
Android 的 匿名共享内存(Ashmem) 基于 Linux 的共享内存,都是在临时文件系统(tmpfs)上创建虚拟文件,再映射到不同的进程。它可以让多个进程操作同一块内存区域,并且除了物理内存限制,没有其他大小限制。相对于 Linux 的共享内存,Ashmem 对内存的管理更加精细化,并且添加了互斥锁。Java 层在使用时需要用到 MemoryFile,它封装了 native 代码。
Java 层使用匿名共享内存的4个点:
关于 匿名共享内存 和 mmap 的关系
MemoryFile 在底层是调用了 mmap 将内存映射在了一个虚拟文件上。 两个进程通过 MemoryFile 访问这个虚拟文件对应的内存。
举例实现
一,服务端
aidl文件
- // IMyAidlInterface.aidl
- package com.example.ashmem;
-
- // Declare any non-default types here with import statements
-
- interface IMyAidlInterface {
- ParcelFileDescriptor getPfd();
- }
- public class MyService extends Service {
- @Override
- public void onCreate() {
- super.onCreate();
- }
-
- IMyAidlInterface.Stub myAidlInterface=new IMyAidlInterface.Stub() {
- @Override
- public ParcelFileDescriptor getPfd() throws RemoteException {
- return createMemory();
- }
- };
-
- @Nullable
- @Override
- public IBinder onBind(Intent intent) {
- return myAidlInterface;
- }
-
-
- //创建共享内存区域
- private ParcelFileDescriptor createMemory() {
- MemoryFile memoryFile=null;
- byte[] bytes =readFile(new File(getFilesDir().getPath(),"image.jpg"));
- try {
- //创建内存对象 参数一:name 参数二:开辟的内存大小
- memoryFile=new MemoryFile("test_memory",1024*4);
- //将数据写入到内存当中
- memoryFile.getOutputStream().write(bytes);
- //通过反射获取到getFileDescriptor方法,注意
- Method method = MemoryFile.class.getDeclaredMethod("getFileDescriptor");
- //得到文件描述符
- FileDescriptor fd = (FileDescriptor) method.invoke(memoryFile);
- //将文件描述符返回
- return ParcelFileDescriptor.dup(fd);
- } catch (IOException e) {
- e.printStackTrace();
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
- return null;
- }
-
-
- //file文件读取成byte[]
- public static byte[] readFile(File file) {
- RandomAccessFile rf = null;
- byte[] data = null;
- try {
- rf = new RandomAccessFile(file, "r");
- data = new byte[(int) rf.length()];
- rf.readFully(data);
- } catch (Exception exception) {
- exception.printStackTrace();
- } finally {
- closeQuietly(rf);
- }
- return data;
- }
- //关闭读取file
- public static void closeQuietly(Closeable closeable) {
- try {
- if (closeable != null) {
- closeable.close();
- }
- } catch (Exception exception) {
- exception.printStackTrace();
- }
- }
- }
二,客户端
拿到fd写入到文件中即可:
- public class MainActivity extends AppCompatActivity implements View.OnClickListener {
-
- private static final String TAG = "MainActivity";
- IMyAidlInterface aidl;
- ParcelFileDescriptor pfd = null;
- private ServiceConnection connection;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- String filePath = this.getFilesDir().getPath();
- File file = new File(filePath + "/image.jpg");
- connection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- aidl = IMyAidlInterface.Stub.asInterface(service);
- try {
- pfd = aidl.getPfd();
- FileDescriptor fileDescriptor = pfd.getFileDescriptor();
- FileInputStream inputStream=new FileInputStream(fileDescriptor);
- file.createNewFile();
- FileOutputStream fo = new FileOutputStream(file);
- int read = inputStream.read();
- while (read != -1) {
- fo.write(read);
- read = inputStream.read();
- }
- //关闭流
- fo.flush();
- fo.close();
- inputStream.close();
-
- // Log.i(TAG,"接收到的数据:"+new String(content,"UTF-8"));
- } catch (RemoteException | IOException e) {
- e.printStackTrace();
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
-
- }
- };
- findViewById(R.id.bindService).setOnClickListener(this);
-
-
- }
-
- private void bindService() {
- Intent intent = new Intent();
- intent.setComponent(new ComponentName("com.example.ashmem", "com.example.ashmem.MyService"));
- boolean isbind = bindService(intent, connection, Context.BIND_AUTO_CREATE);
- Log.i(TAG, "bindService: "+isbind);
- }
-
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.bindService:
- bindService();
- break;
- default:
- break;
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。