我在可绘制文件夹中有高分辨率图像(2588 * 1603)。如果我使用下面的代码(1)为imageView设置它我没有得到OOM异常和按预期分配的图像:
public class MainActivity extends ActionBarActivity{
private ImageView mImageView;
int mImageHeight = 0;
int mImageWidth = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.imageView);
mImageView.setScaleType(ScaleType.FIT_CENTER);
BitmapFactory.Options sizeOption = new BitmapFactory.Options();
sizeOption.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.drawable.a, sizeOption);
mImageHeight = sizeOption.outHeight;
mImageWidth = sizeOption.outWidth;
mImageView.post(new Runnable() {
@Override
public void run() {
try {
BitmapRegionDecoder bmpDecoder = BitmapRegionDecoder
.newInstance(getResources().openRawResource(R.drawable.a),true);
Rect rect = new Rect(0,0,mImageWidth, mImageHeight);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inDensity = getResources().getDisplayMetrics().densityDpi;
Bitmap bmp = bmpDecoder.decodeRegion(rect, options);
mImageView.setImageBitmap(bmp);
} catch (NotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
请注意,rect size与图片大小完全相同。
但如果我使用其他方法,例如2或3,我会得到OOM。
2) mImageView.setBackgroundResource(R.drawable.a);
3) Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.a);
mImageView.setImageBitmap(bmp);
1和2,3有什么区别?
(我知道如何解决OOM,我只是想知道其中的差异)
答案 0 :(得分:2)
这是BitmapRegionDecoder#decodeRegion
:
public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) {
checkRecycled("decodeRegion called on recycled region decoder");
if (rect.left < 0 || rect.top < 0 || rect.right > getWidth()
|| rect.bottom > getHeight())
throw new IllegalArgumentException("rectangle is not inside the image");
return nativeDecodeRegion(mNativeBitmapRegionDecoder, rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top, options);
}
如您所见,它只是调用本机方法。我不太了解C ++,看看该方法是否缩小了位图(根据您的inDensity
标志)。
另外两种方法使用相同的本机方法(nativeDecodeAsset
)来获取位图。
2号缓存 drawable,因此需要更多内存。
经过大量操作(检查位图是否已经预加载或兑现等),它调用本机方法来获取位图。然后,它缓存drawable并设置背景图像。
Number 3非常简单,它在几次操作后调用了一个本机方法。
<小时/> 结论:对我来说,很难说这里适用哪种情况,但它应该是这两种情况中的一种。
inDensity
标志),因此需要更少的内存。 我建议你调试这个问题。在你的Manifest中,设置android:largeHeap="true"
以获得更多内存。然后,运行3种不同的尝试并记录堆大小和位图分配的字节。
long maxMemory = Runtime.getRuntime().maxMemory();
long usedMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
long freeMemory = maxMemory - usedMemory;
long bitmapSize = bmp.getAllocationByteCount();
这将为您提供更好的概述。
答案 1 :(得分:-1)
图片太多细节导致内存不足。
摘要:1使用缩放位图; 2,3加载完整的详细drawable(这会导致内存不足),然后调整大小并将其设置为imageview。
1
Bitmap bmp = bmpDecoder.decodeRegion(rect, options);
the constructor(InputStream is, boolean isShareable) use the stream,不会耗尽内存。
使用BitmapFactory.Options和BitmapRegionDecoder将缩小位图。
2,3
Drawable d = mContext.getDrawable(mResource);
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.a);
没有缩放选项,整个画面将加载到内存
抱歉英语。
也许帮助你。
答案 2 :(得分:-1)
由于此原因,您没有获得OOM异常
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
已经给出了here
public Bitmap.Config inPreferredConfig
在API级别1中添加
如果这是非null,解码器将尝试解码到此内部配置。如果它为null,或者无法满足请求,解码器将尝试根据系统的屏幕深度和原始图像的特征选择最佳匹配配置,例如它是否具有每像素alpha(需要同样的配置)一样)。默认情况下,图像加载了ARGB_8888配置。