1

I have an ImageView with a custom background which is basically with two states, normal and pressed (and images for each). The imageview, with the background is defined in xml. Normally, everything works fine, but after a significant amount(20+) of continuous orientation changes (landscape to portrait and so on) the app crashes with the following error:

12-30 04:13:38.762: E/AndroidRuntime(29771):    FATAL EXCEPTION: main
12-30 04:13:38.762: E/AndroidRuntime(29771):    java.lang.RuntimeException: Unable to start activity ComponentInfo{MyActivity}: android.view.InflateException: Binary XML file line #39: Error inflating class <unknown
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2264)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2314)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3778)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.app.ActivityThread.access$700(ActivityThread.java:144) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1323)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.os.Handler.dispatchMessage(Handler.java:99) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.os.Looper.loop(Looper.java:150) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.app.ActivityThread.main(ActivityThread.java:5147) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at java.lang.reflect.Method.invokeNative(Native Method) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at java.lang.reflect.Method.invoke(Method.java:511) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at dalvik.system.NativeStart.main(Native Method) 

12-30 04:13:38.762: E/AndroidRuntime(29771):    Caused by: android.view.InflateException: Binary XML file line #39: Error inflating class <unknown
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.view.LayoutInflater.createView(LayoutInflater.java:613) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.view.LayoutInflater.onCreateView(LayoutInflater.java:660)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:685)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.view.LayoutInflater.rInflate(LayoutInflater.java:746) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.view.LayoutInflater.rInflate(LayoutInflater.java:749) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.view.LayoutInflater.inflate(LayoutInflater.java:489) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.view.LayoutInflater.inflate(LayoutInflater.java:396) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at MyFragment.onCreateView(MyFragment.java:119)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.support.v4.app.Fragment.performCreateView(Fragment.java:1478)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:927)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1086)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1877)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:552)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at myapp.myActivity.onStart(MyActivity.java:161)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1164)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.app.Activity.performStart(Activity.java:5148) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2237)
12-30 04:13:38.762: E/AndroidRuntime(29771):    ... 12 more 

12-30 04:13:38.762: E/AndroidRuntime(29771):    Caused by: java.lang.reflect.InvocationTargetException 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at java.lang.reflect.Constructor.constructNative(Native Method) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at java.lang.reflect.Constructor.newInstance(Constructor.java:417) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.view.LayoutInflater.createView(LayoutInflater.java:587) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    ... 30 more 

12-30 04:13:38.762: E/AndroidRuntime(29771):    Caused by: java.lang.OutOfMemoryError 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:502)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:355)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:785)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.content.res.Resources.loadDrawable(Resources.java:2098) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.content.res.Resources.getDrawable(Resources.java:793) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.graphics.drawable.StateListDrawable.inflate(StateListDrawable.java:173)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:885)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.graphics.drawable.Drawable.createFromXml(Drawable.java:822)
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.content.res.Resources.loadDrawable(Resources.java:2083) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.content.res.TypedArray.getDrawable(TypedArray.java:601) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.view.View.<init>(View.java:3330) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.widget.ImageView.<init>(ImageView.java:114) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    at android.widget.ImageView.<init>(ImageView.java:110) 
12-30 04:13:38.762: E/AndroidRuntime(29771):    ... 33 more

Looking at the "java.lang.OutOfMemoryError" and "StateListDrawable.java:173" it seems to be somehow related to the ImageView background state. How is this happening? I do keep references to the imageview in my fragment but I set them to null in onDestroyView. What might I be doing wrong?

PS. No context saved anywhere.

VenomVendor
  • 15,064
  • 13
  • 65
  • 96
Soham
  • 4,940
  • 3
  • 31
  • 48
  • Do you have inner classes (anonymous or declared) in the Fragment or Activity that could stay alive past the life of the containing class? – Steve M Dec 30 '13 at 00:35
  • Did you try using [LargeHeap](http://developer.android.com/guide/topics/manifest/application-element.html#largeHeap), get memory usage using [getMemoryClass()](http://developer.android.com/reference/android/app/ActivityManager.html#getMemoryClass%28%29) on every orientation & analyse. – VenomVendor Dec 30 '13 at 00:42
  • @svenoaks nope, but let me double check – Soham Dec 30 '13 at 10:31
  • @VenomVendor that is going to be my approach now, going to analyse the heap and see whats taking the memory – Soham Dec 30 '13 at 10:32

3 Answers3

1

You probably have a memory leak. It's possible the whole fragment is being leaked and not just the ImageView. Download MAT, read article: http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html and find out what specifically is leaking and go from there.

Steve M
  • 9,296
  • 11
  • 49
  • 98
  • thanks, this seems to be the way to go, also I found out the ImageView states were backed by a 512x512 image, reducing the size of that has made this much much more stable, now on to finding the other leaks. Will be using mat and updating the results. – Soham Dec 30 '13 at 10:31
  • the reason I mentioned leaks is because it was on OOM happening after many re creates of the view, which seems to indicate something is being retained inappropriately that can't be garbage collected. With a reduced size image, you're only delaying the OOM error (more recreates of the view would be required). – Steve M Dec 30 '13 at 15:31
  • In MAT, after a few screen rotations do a heap dump and see how many instances of the YourFragmentName are on the heap. There should be only 1 if you are leak free. – Steve M Dec 30 '13 at 15:34
0

There are two possible solutions to this, both involving changes to your XML. These are relatively simple compared to rewriting all your Java code.

  1. Simple: lock screen orientation:

    <LinearLayout
     android:orientation="portrait">
    
    <--Your stuff-->
    
    </LinearLayout>
    
  2. Less simple: Create a landscape version of your xml. To do this, create a new folder named "layout-land" in the res directory. Then, create a new xml file in that folder with identical spelling to the portrait version (e.g. portrait: blah123.xml, landscape: blah123.xml). Create your landscape version.

Chips J.
  • 1
  • 4
  • Currently the app is locked to portrait on phones, so I don't come across these leaks, but now I need to enable orientation changes and I need to use MAT and find the leaks. I am already using 2. v14-land etc to host the alternate layouts – Soham Dec 30 '13 at 10:29
  • Oh I see. For solving the dump problem, go with Venom's answer. If it's a recurring problem, I would strongly suggest choosing either landscape or portrait and locking the orientation. Cheers! – Chips J. Dec 31 '13 at 23:17
0

recycle the background drawable

 if(v.getBackground() != null && 
BitmapDrawable.class.isInstance(v.getBackground())) 
{
((BitmapDrawable)v.getBackground()).getBitmap().recycle();
}
LOG_TAG
  • 19,894
  • 12
  • 72
  • 105