Dalvik虚拟机会为应用程序分配固定大小的heap ,如果使用超过了这个heap的大小,且没有可被回收对象,就会报oom。多张较大图片会迅速占用空间造成oom。
我们可以使用一下的方法来减少这种情况的产生:
1.减少单张图片的大小,根据屏幕大小来对bitmap做resize。
private void setImageSrc(ImageView imageView, String imagePath) {
BitmapFactory.Options option = new BitmapFactory.Options();
option.inSampleSize = getImageScale(imagePath);
Bitmap bm = BitmapFactory.decodeFile(imagePath, option);
imageView.setImageBitmap(bm);
}
private static int IMAGE_MAX_WIDTH = 480;
private static int IMAGE_MAX_HEIGHT = 960;
private static int getImageScale(String imagePath) {
BitmapFactory.Options option = new BitmapFactory.Options();
// set inJustDecodeBounds to true, allowing the caller to query the bitmap info without having to allocate the
// memory for its pixels.
option.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imagePath, option);
int scale = 1;
while (option.outWidth / scale >= IMAGE_MAX_WIDTH || option.outHeight / scale >= IMAGE_MAX_HEIGHT) {
scale *= 2;
}
return scale;
}
2.使用软缓存来保存bitmap,在内存不足时虚拟机可快速回收。
3.在Manifest里配置android:largeHeap="true"
同是我们在使用viewpager的时候至少需要同是加载两个bitmap对象,我们可以使用Fragment来作为viewpager里的item,然后在onPause方法里把非当前bitmap干掉,然后在onResume里把当前bitmap拿出来。
又比如需求需要crop后和原图同是存在的情况下,我们无法同是保存两个bitmap对象,因此我们可以使用自定义控件的方法来解决,重写imageview的onLayout以及onDraw方法来实现。通过onLayout方法得到bitmap的width和height,然后重写onDraw方法为:
if (mBitmap != null && mWidth != 0 && mHeight != 0) {
float scaleBitmap = (float) mBitmap.getHeight() / mBitmap.getWidth();
float scaleCanvas = (float) mHeight / mWidth;
Rect rectSrc = null;
if (scaleBitmap <= scaleCanvas) {
int width = (int) (mBitmap.getHeight() / scaleCanvas);
rectSrc = new Rect((mBitmap.getWidth() - width) / 2, 0, (mBitmap.getWidth() + width) / 2, mBitmap.getHeight());
} else {
rectSrc = new Rect(0, 0, mBitmap.getWidth(), (int) (scaleCanvas * mBitmap.getWidth()));
}
Rect rectDst = new Rect(0 + mPadding, 0 + mPadding, mWidth - mPadding, mHeight - mPadding);
canvas.drawColor(mColor);
canvas.drawBitmap(mBitmap, rectSrc, rectDst, null);
} else
super.onDraw(canvas);