Running in API_14 emulator with WVGA800 screen with 24MB heap I am having problems with background images of my views, where it looks like the are drawables are not being released between view navigations and after 3 views are displayed an Out of memory exception occurs inflating a view.
The app starts with a SplashScreenActivity which has a 480x800 PNG as its background image to use for the startup splash screen. The app proceeds to navigate to its next view which also displays a new 480x800 px. The third screen navigation also contains 480x800 PNG and this when the out of memory error occurs. First I tried this with setting the background in the axml layout. then I tried alternative method of setting the background from code in the SplashScreenActivity.OnCreate() and the other two view OnCreate() methods. I read elsewhere that disposing the drawable release it from the mono vm in case this was the problem. Another trick which helped was to force a GC at the beginning of OnCreate() this left 12% of the heap free but this had limited success.
public class SplashScreenActivity: MvxBaseSplashScreenActivity
{
public SplashScreenActivity() : base(Resource.Layout.SplashScreen) { }
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
using (var drawable = Resources.GetDrawable(Resource.Drawable.LoadingScreen))
Window.SetBackgroundDrawable(drawable);
}
}
And the second view
public class GameView : MvxBindingActivityView<GameViewModel>
{
public GameView() { SoundBinding.GameView = this; }
protected override void OnViewModelSet() { SetContentView(Resource.Layout.GameView); }
protected override void OnCreate(Bundle bundle)
{
GC.Collect();
base.OnCreate(bundle);
using (var drawable = Resources.GetDrawable(Resource.Drawable.GameScreenBackground))
Window.SetBackgroundDrawable(drawable);
}
}
After all this the App still runs out of memory on inflating a third similar view with background. Sometimes it will work, and then as screens cycle eventually it occurs. I looked at the heap dump on MAT and I can see two bitmapDrawables of 3.5M in size. I assume these are my two bitmaps. For the 2nd BitmapDrawable I can clearly see the view that is holding onto it. There is another bitmap still in memory but i can't see what its path to GC root is. This must be the first loaded PNG in the first SplashScreenActivity view. Here is its MAT Path to GC roots without weak refs. There is a weak ref holding it as well.
android.graphics.Bitmap @ 0x4134fb08 | 40 | 3,456,056
|- mBitmap android.graphics.drawable.BitmapDrawable @ 0x4134f568 | 64 | 136
| |- mBackgroundDrawable com.android.internal.policy.impl.PhoneWindow @ 0x41356cc8 Native Stack | 200 | 1,168
| |- mBGDrawable com.android.internal.policy.impl.PhoneWindow$DecorView @ 0x41357560 Native Stack| 560 | 968
| '- Total: 2 entries | |
|- mBitmap android.graphics.drawable.BitmapDrawable$BitmapState @ 0x4134f460 | 40 | 40
| '- referent java.lang.ref.WeakReference @ 0x4134ff40 | 24 | 24
'- Total: 2 entries | |
So question time. How do I ensure these drawables are released before the next view is inflated? Is it necessary to set the backgrounds in code rather than the layouts of the views? Do I need to unbindDrawables() by setting callback to null as seen here Drawable vs Single reusable Bitmap better with memory? ? I investigated the OnDestroy() overide of the views, but I found these where not being called before the new view is created. When navigating from one view to another is there away to ensure a view is destroyed and would this help release my resources before the next view is inflated.
Any advice on how better manage these resources in my app would be much appreciated.