我目前正在制作一个 Android 应用程序来修改图像的一些字节。为此,我编写了以下代码:
Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(path));
ByteBuffer buffer = ByteBuffer.allocate(bmp.getWidth()*bmp.getHeight());
bmp.copyPixelsToBuffer(buffer);
return buffer.array();
问题是这种方式使用了过多的堆内存,并抛出OutOfMemoryException
。
我知道我可以让应用程序的堆内存更大,但这似乎不是一个好的设计选择。
是否有更内存友好的方式来更改图像的字节?
最佳答案
看起来托管堆上有两个像素数据副本:
Bitmap
中的未压缩数据-
ByteBuffer
中数据的副本
通过将数据保留在位图中并使用getPixel()
,可以将内存需求减半。/setPixel()
(或者可能使用“批量”变体一次编辑一行),但这会增加一些开销。
根据图像的性质,您也许可以使用不太精确的格式(例如 RGB 565 而不是 8888),从而将内存需求减半。
正如评论之一所述,您可以将数据解压缩到文件,并使用 java.nio.channels.FileChannel#map()
对其进行内存映射。 ,并通过 MappedByteBuffer
访问它。这会增加加载和保存的相当大的开销,并且可能会很烦人,因为您必须完成 ByteBuffer
而不是byte[]
.
另一个选项是使用 android:largeHeap
扩展堆。 ( documented here ),尽管在某些方面您只是推迟了不可避免的事情:您可能会被要求编辑对于“大”堆来说太大的图像。此外,“大”堆的容量因设备而异,就像“正常大小”堆一样。这是否有意义部分取决于您加载的图像有多大。
在执行任何操作之前,我建议使用堆分析工具(例如 this blog post )来查看内存的去向。另外,查看内存不足异常上面的logcat;它应该识别失败的分配的大小。确保它看起来“合理”,即您不会无意中分配比您想象的多得多的资金。
关于java - Android:内存友好的图像字节修改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17217652/