Col*_*lis 114 performance android bitmap out-of-memory
我正在构建一个图像密集型社交应用程序,其中图像从服务器发送到设备.当设备具有较小的屏幕分辨率时,我需要调整设备上的位图大小以匹配其预期的显示大小.
问题是使用createScaledBitmap会导致我在调整大量缩略图图像后遇到大量内存不足错误.
什么是在Android上调整位图大小最有效的内存方式?
Col*_*lis 164
这个答案总结从加载大位图有效地 解释了如何使用inSampleSize来加载缩小的位图版本.
特别是预缩放位图解释了各种方法的细节,如何组合它们,以及哪些是最节省内存的.
在Android上调整具有不同内存属性的位图有三种主要方法:
此API将接收现有位图,并使用您选择的确切尺寸创建新位图.
从好的方面来说,您可以准确地获得您正在寻找的图像尺寸(无论它看起来如何).但缺点是,此API需要现有的位图才能工作.这意味着在创建新的较小版本之前,必须加载,解码图像并创建位图.这在获得精确尺寸方面是理想的,但在额外的内存开销方面却很糟糕.因此,对于大多数倾向于记忆的应用程序开发人员来说,这是一种交易破坏者
BitmapFactory.Options有一个注明的属性inSampleSize,它将在解码时调整图像大小,以避免解码到临时位图.此处使用的此整数值将以1/x缩小的尺寸加载图像.例如,设置inSampleSize为2将返回一半大小的图像,将其设置为4将返回大小为1/4的图像.基本上,图像尺寸总是比源尺寸小一些.
从内存的角度来看,使用inSampleSize是一种非常快速的操作.实际上,它只会将图像的每个第X个像素解码为生成的位图.但是有两个主要问题inSampleSize:
它没有给你准确的分辨率.它只会将位图的大小减小2倍.
它不会产生最佳质量的调整大小.大多数调整大小的滤镜通过读取像素块产生漂亮的图像,然后对它们进行加权以产生所讨论的调整大小的像素.inSampleSize通过读取每几个像素来避免所有这些.结果非常高效,内存不足,但质量却受到影响.
如果你只是处理缩小你的图像的一些pow2大小,并且过滤不是问题,那么你找不到比内存更有效(或性能更高)的方法inSampleSize.
inScaled,inDensity,inTargetDensity标志
如果您需要将图像缩放到的尺寸,这不是等于2的幂,那么你需要的inScaled,inDensity和inTargetDensity旗帜BitmapOptions.当inScaled标志已设置时,系统会得出缩放值除以适用于您的位图inTargetDensity由inDensity值.
mBitmapOptions.inScaled = true;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeResources(getResources(),
mImageIDs, mBitmapOptions);
Run Code Online (Sandbox Code Playgroud)
使用此方法将重新调整图像大小,并对其应用"调整大小过滤器",也就是说,最终结果看起来会更好,因为在调整大小步骤期间已考虑了一些额外的数学运算.但要注意:额外的过滤步骤,需要额外的处理时间,并且可以快速添加大图像,导致调整缓慢,并为过滤器本身提供额外的内存分配.
由于额外的过滤开销,将此技术应用于远大于所需大小的图像通常不是一个好主意.
魔术组合
从内存和性能角度来看,您可以组合这些选项以获得最佳结果.(设置inSampleSize,inScaled,inDensity和inTargetDensity标志)
inSampleSize将首先应用于图像,使其达到下一个比目标尺寸更大的功率.然后,inDensity&inTargetDensity用于将结果缩放到所需的精确尺寸,应用滤镜操作来清理图像.
将这两者结合起来是一个快得多的操作,因为该inSampleSize步骤将减少基于密度的步骤所需的像素数,以应用它的调整大小过滤器.
mBitmapOptions.inScaled = true;
mBitmapOptions.inSampleSize = 4;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth * mBitmapOptions.inSampleSize;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeFile(fileName, mBitmapOptions);
Run Code Online (Sandbox Code Playgroud)
如果您需要将图像适合特定尺寸和更好的过滤,那么这种技术是获得正确尺寸的最佳桥梁,但是在快速,低内存占用操作中完成.
获取图像尺寸
在不解码整个图像的情况下获取图像大小为了调整位图大小,您需要知道传入的尺寸.您可以使用该inJustDecodeBounds标志来帮助您获取图像的尺寸,而无需实际解码像素数据.
// Decode just the boundaries
mBitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileName, mBitmapOptions);
srcWidth = mBitmapOptions.outWidth;
srcHeight = mBitmapOptions.outHeight;
//now go resize the image to the size you want
Run Code Online (Sandbox Code Playgroud)
您可以使用此标志首先解码大小,然后计算适当的值以缩放到目标分辨率.
| 归档时间: |
|
| 查看次数: |
13097 次 |
| 最近记录: |