赞
踩
Android 提供了几种进程间通信的方式,除了Socket,基本都是基于binder实现的。为什么要用共享内存来实现呢?因为binder传输数据被限制在1M,在较大的数据交换一般会使用文件,但效率非常的低,因此使用共享内存是很好的方式。在内存中开辟一块空间,通过binder或者其他方式将fd(文件描述符)传递到客户端或服务端进程,从而实现大文件传输
其中Android提供了封装好的MemoryFile对象,供使用。
具体实现
一,服务端
1,首先在APP内部存储中存放一张图片:路径 data/data/com.example.ashmem_service/files/image.jpg
2,将文件写入到共享内存 并返回ParcelFileDescriptor
2,通过binder将返回的pfd传递给客户端
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 版权所有,并保留所有权利。