基于Android 匿名共享内存实现跨进程实时传输大量图片或数据

aidl传输文件有大小1M限制,单次传输不适合传递大数据,可以通过Android匿名共享内存的方法来解决这个问题, 使用aidl传递共享内存引用ParcelFileDescriptor方式传递图片信息。具体实现如下
一、service端
1.1.aidl文件IIpcService.aidl 定义,这里主要用到pfd参数

interface IIpcService {
	/**
	* Demonstrates some basic types that you can use as parameters
	* and return values in AIDL.
	*/
	// void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
	// double aDouble, String aString);
	void register2Server(String packageName,IIpcServiceListener ipcServiceListener);
	void unregister2Server(String packageName);
	String processClientRequest(String packageName,String clientRequest,inout ParcelFileDescriptor pfd);
}


1.2 service端 处理客户端传递的图片 流 引用ParcelFileDescriptor ,将获取的ParcelFileDescriptor转换成Bitmap 并回调给ui层显示

public String processClientRequest(String packageName, String clientRequest, ParcelFileDescriptor pfd) {

	Log.i(TAG, "processClientRequest 11 packageName:" + packageName
	+ " clientRequest:" + clientRequest + " pfd:" + pfd);
	String ret = clientRequest;
	FileDescriptor fileDescriptor = pfd.getFileDescriptor();
	FileInputStream fis = null;
	try {
		fis = new FileInputStream(fileDescriptor);
		Bitmap rawBitmap = BitmapFactory.decodeStream(fis);
		ret += " process success!";

		Log.i(TAG, "processClientRequest 222 rawBitmap ByteCount:" + rawBitmap.getByteCount() + " mUiShow:" + mUiShow);

		if (null != mUiShow) {
			mUiShow.showBitmap(rawBitmap);
		}
	} catch (Exception e) {
		Log.i(TAG, "processClientRequest 22 error:" + e);
		e.printStackTrace();
	} finally {
		try {
			if (fis != null) {
				fis.close();
			}
		} catch (IOException e) {
				Log.i(TAG, "processClientRequest 33 error:" + e);
		}
	}

	Log.i(TAG, "processClientRequest 22 end ret:" + ret);
	return ret;
}


1.3 也可以处理客户端传递的字节数组 数据引用,处理代码如下

public String processClientRequest(String packageName, String clientRequest, ParcelFileDescriptor pfd) {

	Log.i(TAG, "processClientRequest 11 packageName:" + packageName
	+ " clientRequest:" + clientRequest + " pfd:" + pfd);
	String ret = clientRequest;
	FileDescriptor fileDescriptor = pfd.getFileDescriptor();
	FileInputStream fis = null;
	try {
		fis = new FileInputStream(fileDescriptor);

		byte [] content = new byte[5];
		fis.read(content);
		Log.i(TAG, "processClientRequest 111 content:" + content);
		for(int i=0;i<content.length;i++){
			Log.i(TAG, "processClientRequest 113 content["+i+"]=" + content[i]);
		}
	} catch (Exception e) {
		Log.i(TAG, "processClientRequest 33 error:" + e);
		e.printStackTrace();
	} finally {
		try {
			if (fis != null) {
				fis.close();
			}
		} catch (IOException e) {
			Log.i(TAG, "processClientRequest 44 error:" + e);
		}
	}

	Log.i(TAG, "processClientRequest 55 end ret:" + ret);
	return ret;
}


二客户端
2.1 客户端连接到service后,调用接口 传递图片文件引用 ParcelFileDescriptor

String path = "/sdcard/lilei/20230207161749238.jpg";
public ParcelFileDescriptor getPfd() {
	ParcelFileDescriptor pfd = null;
	try {
		pfd = ParcelFileDescriptor.open(new File(path), MODE_READ_WRITE);
	} catch (FileNotFoundException e) {
		throw new RuntimeException(e);
	}
	Log.i(TAG, "getPfd() pfd:" + pfd);
	return pfd;
}

public String sendFile(String requestJson) {
	Log.i(TAG, "sendFile() requestJson:" + requestJson);
	if (null != mFtIpcManager) {
		return mFtIpcManager.processClientRequest(requestJson, getPfd());
	}
	return "error";
}


2.2 客户端也可以传递 byte数组

public ParcelFileDescriptor getTextPfd() {
	ParcelFileDescriptor pfd = null;
	try {
		MemoryFile memoryFile = new MemoryFile("test", 1024);
		Method method = MemoryFile.class.getDeclaredMethod("getFileDescriptor");
		FileDescriptor des = (FileDescriptor) method.invoke(memoryFile);
		pfd = ParcelFileDescriptor.dup(des);
		//向内存中写入字节数组
		memoryFile.getOutputStream().write(new byte[]{1,2,5,4,3});
		//关闭流
		memoryFile.getOutputStream().close();
		memoryFile.close();

	} catch (IOException e) {
		throw new RuntimeException(e);
	} catch (InvocationTargetException e) {
		throw new RuntimeException(e);a
	} catch (NoSuchMethodException e) {
		throw new RuntimeException(e);
	} catch (IllegalAccessException e) {
		throw new RuntimeException(e);
	}
	Log.i(TAG, "getTextPfd() pfd:" + pfd);
	return pfd;
}
public String sendFile(String requestJson) {
	Log.i(TAG, "sendFile() requestJson:" + requestJson);
	if (null != mFtIpcManager) {
		return mFtIpcManager.processClientRequest(requestJson, getTextPfd());
	}
	return "error";
}


2.3 客户端也可以传递Bitmap数据,需要先将Bitmap转换成 byte数组,service端接收同1.2

public ParcelFileDescriptor getBitmapPfd() {
	ParcelFileDescriptor pfd = null;

	Bitmap bitmap= BitmapFactory.decodeResource(FtClientApp.getAppContext().getResources(), R.drawable.btn_send);
	//将Bitmap转成字节数组
	ByteArrayOutputStream stream = new ByteArrayOutputStream();
	bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
	byte[] byteArray = stream.toByteArray();

	try {
		MemoryFile memoryFile = new MemoryFile("test", bitmap.getByteCount());
		Method method = MemoryFile.class.getDeclaredMethod("getFileDescriptor");
		FileDescriptor des = (FileDescriptor) method.invoke(memoryFile);
		pfd = ParcelFileDescriptor.dup(des);
		//向内存中写入字节数组
		memoryFile.getOutputStream().write(byteArray);
		//关闭流
		memoryFile.getOutputStream().close();
		memoryFile.close();

	} catch (IOException e) {
		throw new RuntimeException(e);
	} catch (InvocationTargetException e) {
		throw new RuntimeException(e);
	} catch (NoSuchMethodException e) {
		throw new RuntimeException(e);
	} catch (IllegalAccessException e) {
		throw new RuntimeException(e);
	}
	Log.i(TAG, "getPfd() pfd:" + pfd);
	return pfd;
}
public String sendFile(String requestJson) {
	Log.i(TAG, "sendFile() requestJson:" + requestJson);
	if (null != mFtIpcManager) {
		return mFtIpcManager.processClientRequest(requestJson, getBitmapPfd());
	}
	return "error";
}

PS:这里也可以共享内存传递大字符串,只是需要将字符串和字节数组转换一下再传递,转换实现如下。
1.string 字符串转换成 byte[] 数组

String str = "reagan";
byte[] srtbyte = str.getBytes();

2.byte[] 数组转换成 string字符串

String res = new String(srtbyte);
或者
String res = new String(srtbyte,"UTF-8");
System.out.println(res);

----------

如下服务端1.2 log 所示,服务端可以接受客户端2.3发送 的 31M左右的图片数据

2024-01-09 01:14:45.797 11247-11267 SimpleTestActivity com.android.demo.lileidemo I showBitmap() bitmap:android.graphics.Bitmap@3fe9243 getByteCount:33177600
2024-01-09 01:14:45.798 11247-11267 lileiDemo_...sitoryImpl com.android.demo.lileidemo I processClientRequest 55 end ret:image process success!

  • 14
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android进程数据传输可以通过使用Binder机制实现。Binder是一种进程通信的机制,它允许一个进程调用另一个进程的方法,同时也支持进程传输数据。下面是一个简单的演示: 1.定义一个AIDL接口文件,例如IMyAidlInterface.aidl,其中包含需要进程调用的方法: ```aidl interface IMyAidl { int add(int a, int b); } ``` 2.在服务端实现该接口: ```java public class MyService extends Service { private final IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() { @Override public int add(int a, int b) throws RemoteException { return a + b; } }; @Nullable @Override public IBinder onBind(Intent intent) { return mBinder; } } ``` 3.在客户端绑定服务并调用接口方法: ```java private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { IMyAidlInterface myAidlInterface = IMyAidlInterface.Stub.asInterface(iBinder); try { int result = myAidlInterface.add(1, 2); Log.d(TAG, "result: " + result); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName componentName) { } }; Intent intent = new Intent(); intent.setComponent(new ComponentName("com.example.myapp", "com.example.myapp.MyService")); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); ``` 在上述代码中,客户端通过bindService()方法绑定服务,然后通过IMyAidlInterface接口调用服务端的add()方法,最后得到结果并打印。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值