6

I am using very simple code to show gallery of images stored as drawables. All images are less than 200kb in size and 1024x576 pixels resolution.

my code works fine on 4 devices I tested and for the most of my users. But some of them keep getting famous vm budget memory issue.

he is my code:

in onCreate() method of my activity:

// set Factory for Image Switcher
imageSwitcher = (ImageSwitcher) findViewById(R.id.ImageSwitcher);
imageSwitcher.setFactory(new MyImageSwitcherFactory());

Factory class:

private class MyImageSwitcherFactory implements ViewFactory {
public View makeView() {
    ImageView imageView = new ImageView(Main.this);
    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
    imageView.setLayoutParams(new ImageSwitcher.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
    return imageView;
}
}

and the code to show images:

try {
    // this is internal image loaded from drawables
    imageSwitcher.setImageResource(images.get(imageNumber - 1).imageResourceID);

} catch (Exception e) {
    // no image will be shown
}

error happens on some phones (very very small percent of downloads) in try/catch block and with some phones activity cannot even start at all.

I read about recycling bitmaps and memory leaks issues, but my activity is run in sigle-top mode and not recreated on orientation changes, so it is always the same activity. I also do not use bitmaps directly.

Can I improve my code somehow to get rid of this error?

first type of error:

java.lang.OutOfMemoryError: bitmap size exceeds VM budget
    at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:464)
    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:340)
    at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
    at android.content.res.Resources.loadDrawable(Resources.java:1705)
    at android.content.res.Resources.getDrawable(Resources.java:580)
    at android.widget.ImageView.resolveUri(ImageView.java:548)
    at android.widget.ImageView.setImageResource(ImageView.java:270)
    at android.widget.ImageSwitcher.setImageResource(ImageSwitcher.java:41)
    at com.mobilebabytoys.animalsoundsfree.Main.showNextImage(Main.java:356)
    at com.mobilebabytoys.animalsoundsfree.Main.access$0(Main.java:284)
    at com.mobilebabytoys.animalsoundsfree.Main$MyGestureDetector.onFling(Main.java:861)
    at android.view.GestureDetector.onTouchEvent(GestureDetector.java:517)
    at com.mobilebabytoys.animalsoundsfree.Main$8.onTouch(Main.java:218)
    at android.view.View.dispatchTouchEvent(View.java:3705)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:874)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:924)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:924)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1695)
    at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1116)
    at android.app.Activity.dispatchTouchEvent(Activity.java:2068)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1679)
    at android.view.ViewRoot.handleMessage(ViewRoot.java:1697)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:123)
    at android.app.ActivityThread.main(ActivityThread.java:4568)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:521)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
    at dalvik.system.NativeStart.main(Native Method)

second type of error:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mobilebabytoys.animalsoundsfree/com.mobilebabytoys.animalsoundsfree.Main}: android.view.InflateException: Binary XML file line #15: Error inflating class <unknown>
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2596)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2621)
    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3812)
    at android.app.ActivityThread.access$2300(ActivityThread.java:126)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1936)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:123)
    at android.app.ActivityThread.main(ActivityThread.java:4595)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:521)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
    at dalvik.system.NativeStart.main(Native Method)
Caused by: android.view.InflateException: Binary XML file line #15: Error inflating class <unknown>
    at android.view.LayoutInflater.createView(LayoutInflater.java:513)
    at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:563)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:618)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:407)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
    at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:207)
    at android.app.Activity.setContentView(Activity.java:1629)
    at com.mobilebabytoys.animalsoundsfree.Main.onCreate(Main.java:154)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2544)
    ... 12 more
Caused by: java.lang.reflect.InvocationTargetException
    at android.widget.ImageButton.<init>(ImageButton.java:78)
    at java.lang.reflect.Constructor.constructNative(Native Method)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:446)
    at android.view.LayoutInflater.createView(LayoutInflater.java:500)
    ... 23 more
Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
    at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:464)
    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:340)
    at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
    at android.content.res.Resources.loadDrawable(Resources.java:1705)
    at android.content.res.Resources.getDrawable(Resources.java:580)
    at android.graphics.drawable.StateListDrawable.inflate(StateListDrawable.java:160)
    at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:788)
    at android.graphics.drawable.Drawable.createFromXml(Drawable.java:729)
    at android.content.res.Resources.loadDrawable(Resources.java:1690)
    at android.content.res.TypedArray.getDrawable(TypedArray.java:548)
    at android.widget.ImageView.<init>(ImageView.java:115)
    at android.widget.ImageButton.<init>(ImageButton.java:82)
    ... 27 more
android.view.InflateException: Binary XML file line #15: Error inflating class <unknown>
    at android.view.LayoutInflater.createView(LayoutInflater.java:513)
    at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:563)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:618)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:407)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
    at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:207)
    at android.app.Activity.setContentView(Activity.java:1629)
    at com.mobilebabytoys.animalsoundsfree.Main.onCreate(Main.java:154)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2544)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2621)
    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3812)
    at android.app.ActivityThread.access$2300(ActivityThread.java:126)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1936)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:123)
    at android.app.ActivityThread.main(ActivityThread.java:4595)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:521)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
    at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.reflect.InvocationTargetException
    at android.widget.ImageButton.<init>(ImageButton.java:78)
    at java.lang.reflect.Constructor.constructNative(Native Method)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:446)
    at android.view.LayoutInflater.createView(LayoutInflater.java:500)
    ... 23 more
Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
    at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:464)
    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:340)
    at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
    at android.content.res.Resources.loadDrawable(Resources.java:1705)
    at android.content.res.Resources.getDrawable(Resources.java:580)
    at android.graphics.drawable.StateListDrawable.inflate(StateListDrawable.java:160)
    at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:788)
    at android.graphics.drawable.Drawable.createFromXml(Drawable.java:729)
    at android.content.res.Resources.loadDrawable(Resources.java:1690)
    at android.content.res.TypedArray.getDrawable(TypedArray.java:548)
    at android.widget.ImageView.<init>(ImageView.java:115)
    at android.widget.ImageButton.<init>(ImageButton.java:82)
    ... 27 more
java.lang.reflect.InvocationTargetException
    at android.widget.ImageButton.<init>(ImageButton.java:78)
    at java.lang.reflect.Constructor.constructNative(Native Method)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:446)
    at android.view.LayoutInflater.createView(LayoutInflater.java:500)
    at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:563)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:618)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:407)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
    at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:207)
    at android.app.Activity.setContentView(Activity.java:1629)
    at com.mobilebabytoys.animalsoundsfree.Main.onCreate(Main.java:154)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2544)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2621)
    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3812)
    at android.app.ActivityThread.access$2300(ActivityThread.java:126)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1936)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:123)
    at android.app.ActivityThread.main(ActivityThread.java:4595)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:521)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
    at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
    at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:464)
    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:340)
    at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
    at android.content.res.Resources.loadDrawable(Resources.java:1705)
    at android.content.res.Resources.getDrawable(Resources.java:580)
    at android.graphics.drawable.StateListDrawable.inflate(StateListDrawable.java:160)
    at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:788)
    at android.graphics.drawable.Drawable.createFromXml(Drawable.java:729)
    at android.content.res.Resources.loadDrawable(Resources.java:1690)
    at android.content.res.TypedArray.getDrawable(TypedArray.java:548)
    at android.widget.ImageView.<init>(ImageView.java:115)
    at android.widget.ImageButton.<init>(ImageButton.java:82)
    ... 27 more
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
    at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:464)
    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:340)
    at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
    at android.content.res.Resources.loadDrawable(Resources.java:1705)
    at android.content.res.Resources.getDrawable(Resources.java:580)
    at android.graphics.drawable.StateListDrawable.inflate(StateListDrawable.java:160)
    at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:788)
    at android.graphics.drawable.Drawable.createFromXml(Drawable.java:729)
    at android.content.res.Resources.loadDrawable(Resources.java:1690)
    at android.content.res.TypedArray.getDrawable(TypedArray.java:548)
    at android.widget.ImageView.<init>(ImageView.java:115)
    at android.widget.ImageButton.<init>(ImageButton.java:82)
    at android.widget.ImageButton.<init>(ImageButton.java:78)
    at java.lang.reflect.Constructor.constructNative(Native Method)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:446)
    at android.view.LayoutInflater.createView(LayoutInflater.java:500)
    at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:563)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:618)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:407)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
    at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:207)
    at android.app.Activity.setContentView(Activity.java:1629)
    at com.mobilebabytoys.animalsoundsfree.Main.onCreate(Main.java:154)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2544)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2621)
    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3812)
    at android.app.ActivityThread.access$2300(ActivityThread.java:126)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1936)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:123)
    at android.app.ActivityThread.main(ActivityThread.java:4595)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:521)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
    at dalvik.system.NativeStart.main(Native Method)

my activity layout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/MainLayout"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:keepScreenOn="true">
    <ImageSwitcher
        android:keepScreenOn="true"
        android:id="@+id/ImageSwitcher"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
    </ImageSwitcher>

</RelativeLayout>
mishkin
  • 5,932
  • 8
  • 45
  • 64

1 Answers1

5

About the Bitmap error:
You should consider down sampling your bitmap and resize them before creating them in memory. take a look at the following thread Handling Large Bitmaps

The second errors is cause the runtime is unable to create a view hierarchy from the Layout XML. Are you using a custom view in your layout?

Edit: your layout XML looks correct and now that you've posted entire dump, to me the only problem is size of the Bitmap. I still maintain that you will have to down sample the images.

What is the format of your images; a 1024 x 576 JPEG image could be too big when decompressed into Bitmap.

See if any of these discussions give any pointers: 1, 2, 3.

Community
  • 1
  • 1
Samuh
  • 36,316
  • 26
  • 109
  • 116
  • thanks for the answer but I do not see a need to downscale - pictures are less than 200kb which should be fine. besides downscaling is not free - it takes time. Second error is also "Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget". I do not use custom view on that activity – mishkin Mar 03 '11 at 03:48
  • Can you go through the logs again and check if VM tried 200kb allocation or was it more than that? – Samuh Mar 03 '11 at 03:51
  • done, hope it helps. I also played with memory analyzer and i did not find any leaks after clicking like crazy on my pictures for a few minutes. I cannot even reproduce these errors on 4 devices i tried and emulator. – mishkin Mar 03 '11 at 04:16
  • Yes but you do realize that the image is already being downscaled whether you like it or not as each time you load it (assuming your device's screen < the res of the image), it will be scaled to fit the view each time within the drawable, plus the way you have it, it will be done on the UI thread so it's a little expensive anyways. I think Samuh is correct though, predownscale the image (in a background thread) and then save it use that bitmap as the content to be displayed. You can store the Bitmap in memory and have Bitmap drawables created around the Bitmap inside of each imageview. – Greg Giacovelli Mar 07 '11 at 02:59
  • Updated answer and added links to similar discussions. – Samuh Mar 09 '11 at 06:53
  • 2
    @mishkin Your images are 200KB *compressed*. When decompressed into RAM they will be ~2200KB if using a 32bpp bitmap (more than 2MB!) or half that if using 16bpp. – Reuben Scratton Mar 09 '11 at 20:15
  • yes, it is JPG, even if they are 2Mb, I still have plenty of space left on heap, right? Thanks, Samuh, I will try downscaling, but sounds like too much work for just showing a simple image using standard view. How gallery apps work? camera takes 6 mpx images and show them just fine (not preview but actual image) – mishkin Mar 10 '11 at 03:46
  • Create a BitmapDrawable from your image resources and set the sampleSize to 2/4. BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2; – Abhinav Mar 10 '11 at 10:50