我正在构建一个图像密集型的社交应用程序,其中图像从服务器发送到设备。当设备具有较小的屏幕分辨率时,我需要在设备上调整位图的大小以匹配其预期的显示大小。
问题是使用createScaledBitmap会导致我在调整一大堆缩略图图像后遇到很多内存不足错误。
在Android上调整位图大小的最节省内存的方法是什么?
问题是使用createScaledBitmap会导致我在调整一大堆缩略图图像后遇到很多内存不足错误。
在Android上调整位图大小的最节省内存的方法是什么?
好的一面是,你可以得到你想要的完全尺寸的图像(无论它看起来如何)。但是不好的一面是,这个API需要一个现有的位图才能工作。这意味着在能够创建新的、更小的版本之前,必须加载、解码并创建位图。从获得精确的尺寸方面来说,这是理想的,但从额外的内存开销方面来说却很糟糕。因此,对于大多数注重内存的应用程序开发人员来说,这有点成为了一个致命问题。
BitmapFactory.Options
有一个被称为inSampleSize
的属性,它将在解码图像时调整图像大小,以避免需要解码到临时位图。这里使用的整数值将以1/x的缩小比例加载图像。例如,将inSampleSize
设置为2会返回一个尺寸减半的图像,将其设置为4会返回一个尺寸为原始图像的1/4。基本上,图像大小总是比源大小小二的幂。
从内存角度来看,使用inSampleSize
是一项非常快速的操作。实际上,它只会将您图像中的每X个像素解码为最终位图。然而,inSampleSize
存在两个主要问题:
它无法给出精确的分辨率。它只能将位图的大小减小2的某个幂次。
它不能产生最佳质量的调整大小效果。大多数调整大小滤镜通过读取像素块并加权处理这些像素块以产生所需的调整后的像素,从而生成外观良好的图像。 inSampleSize
通过仅读取每几个像素来避免所有这些操作。结果具有相当高的性能和低内存,但质量会受到影响。
如果您只需要通过某些pow2大小缩小图像,并且过滤不是问题,则无法找到比inSampleSize
更节省内存(或更高效)的方法。
inScaled、inDensity、inTargetDensity标志
如果您需要将图像缩放到不是2的幂次方的尺寸,则需要使用BitmapOptions
的inScaled
、inDensity
和inTargetDensity
标志。当设置了inScaled
标志时,系统将通过将inTargetDensity
除以inDensity
值来推导应用于位图的缩放值。请注意,保留HTML标签。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);
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);
// 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