Reputation: 2829
I have one image about 1948X674 dimension and 104kb in size. It gives OutOfMemoryError on Samsung galaxy S3. I am showing this image in horizontal scrollview. Here is my xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Panorama" >
<HorizontalScrollView
android:id="@+id/hscroll"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_above="@+id/tapToEnter"
android:scrollbars="none" >
<ImageView
android:id="@+id/imgPanorama"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
</HorizontalScrollView>
<Button
android:id="@+id/tapToEnter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="Tap to enter" />
</RelativeLayout>
and i am setting image to it programatically. decodeSampledBitmapFromResource() i am using from Loading Large Bitmap Efficiently .
Bitmap bmp;
try
{
BitmapDrawable bd=(BitmapDrawable)getResources().getDrawable(R.drawable.panorama);
reqwidth=bd.getIntrinsicWidth();
reqheight = bd.getIntrinsicHeight();
}catch(OutOfMemoryError oom)
{
oom.printStackTrace();
}
bmp=decodeSampledBitmapFromResource(getResources(),R.drawable.panorama, reqwidth, reqheight);
imgPanorama.setImageBitmap(bmp);
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inPurgeable=true;
/*options.inDither=false; //Disable Dithering mode
options.inPurgeable=true; //Tell to gc that whether it needs free memory, the Bitmap can be cleared
options.inInputShareable=true; //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
options.inTempStorage=new byte[32 * 1024];
*/
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if(bmp!=null && !bmp.isRecycled())
{
bmp.recycle();
bmp=null;
}
}
Here is my logcat when i start activity.
03-20 11:20:36.175: I/dalvikvm-heap(30452): Grow heap (frag case) to 17.982MB for 5251824-byte allocation
03-20 11:20:36.260: I/dalvikvm-heap(30452): Grow heap (frag case) to 38.014MB for 21007248-byte allocation
03-20 11:20:36.385: I/dalvikvm-heap(30452): Grow heap (frag case) to 38.016MB for 5251824-byte allocation
03-20 11:20:36.480: I/dalvikvm-heap(30452): Grow heap (frag case) to 58.050MB for 21007248-byte allocation
Upvotes: 2
Views: 2151
Reputation: 12656
Bitmap.recycle()
is your friend because it allows the image's pixel data to be freed much more quickly than manual or automatic garbage collection will do the same job. Therefore, when you are finished with a large image, it can be a good idea to recycle()
it before allowing it to go out of scope. Of course it will be automatically garbage collected after it goes out of scope, but recycle()
will immediately release the vast majority of the memory used by the Bitmap
.
For example, you may choose to recycle()
after copying a Bitmap
to a UI element:
Bitmap bmp;
bmp=decodeSampledBitmapFromResource(getResources(),R.drawable.panorama, reqwidth, reqheight);
imgPanorama.setImageBitmap(bmp);
// Free the pixel data immediately in order to keep heap from growing out of control.
// This is especially useful while displaying multiple images.
bmp.recycle();
You may also experiment with smaller values of reqwidth
and reqheight
, which will allow larger calculated inSampleSize
so that your Bitmap
will use significantly less memory.
Upvotes: 2