2

I am creating a simple Android app and I'm investigating some out-of-memory problems. The app consist of 6 activities, each having a theme, some buttons, some images etc. The themes are setup like this:

<?xml version="1.0" encoding="UTF-8" ?>
<resources>
  <style name="Theme.Normal" parent="android:Theme">
    <item name="android:windowBackground">@drawable/bg640x960</item>
    <item name="android:windowNoTitle">true</item>
  </style>
  <style name="Theme.Blur" parent="android:Theme">
    <item name="android:windowBackground">@drawable/bgblur640x960</item>
    <item name="android:windowNoTitle">true</item>
  </style>
</resources>

In total 14 images are used (4 of them being big: 640x960 pixels).

My UI is made in xml using the Xamarin Designer and e.g. the ImageViews are set up like this:

<ImageView
    p1:src="@drawable/logo"
    p1:layout_width="match_parent"
    p1:layout_height="match_parent"
    p1:id="@+id/imageView2" />

Not much is going on in OnCreate() etc.

I'm navigating between the activities like this:

var intent = new Intent(this, typeof(InfoPage));
StartActivity(intent);

While I am navigating between the activities at some point I am getting an out-of-memory exception:

at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () <0x00028>
at Android.Runtime.JNIEnv.CallNonvirtualVoidMethod (intptr,intptr,intptr,Android.Runtime.JValue[]) <0x000e7>
at Android.App.Activity.SetContentView (int) <0x001e7>
at SPS.Android.QuestionPage.OnCreate (Android.OS.Bundle) <0x0005b>
at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (intptr,intptr,intptr) <0x0005b>
at (wrapper dynamic-method) object.d6c8c709-4564-4172-820d-ca61f7c48e36 (intptr,intptr,intptr) <0x00043>

  --- End of managed exception stack trace ---
android.view.InflateException: Binary XML file line #1: Error inflating class <unknown>
    at android.view.LayoutInflater.createView(LayoutInflater.java:626)
    at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
    at android.view.LayoutInflater.onCreateView(LayoutInflater.java:675)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:700)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:761)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:769)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:769)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:498)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:398)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:354)
    at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:361)
    at android.app.Activity.setContentView(Activity.java:1956)
    at sps.android.QuestionPage.n_onCreate(Native Method)
    at sps.android.QuestionPage.onCreate(QuestionPage.java:38)
    at android.app.Activity.performCreate(Activity.java:5372)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1104)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2257)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2349)
    at android.app.ActivityThread.access$700(ActivityThread.java:159)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1316)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:5419)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025)
    at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Constructor.constructNative(Native Method)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
    at android.view.LayoutInflater.createView(LayoutInflater.java:600)
    ... 27 more
Caused by: java.lang.OutOfMemoryError
    at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:596)
    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444)
    at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:832)
    at android.content.res.Resources.loadDrawable(Resources.java:2988)
    at android.content.res.TypedArray.getDrawable(TypedArray.java:602)
    at android.view.View.<init>(View.java:3563)
    at android.widget.TextView.<init>(TextView.java:881)
    at android.widget.Button.<init>(Button.java:108)
    at android.widget.Button.<init>(Button.java:104)

My question is: are the images/drawables used in the UI shared between the UI elements?

E.g. 4 of the 6 activities share the same background image (in the theme) - hopefully these background images are not duplicated 4 times in memory?

Each activity has buttons with background image - the background image is only loaded once, right?

Or should I implemented a Drawable cache (e.g. load and decode all images in memory on startup and hold Bitmaps) and manually set the drawable on each UI element in code? (that seems like a lot of work).

My APK is only 8 MB and I'm cannot understand what can cause out-of-memory problems in such a simple app.

I'm using Xamarin.Android. The crash happens e.g. on a Samsung Galaxy S3 with 1GB memory.

  • 8 MB too big apk reduce the size of apk – Naveen Tamrakar Oct 28 '14 at 08:06
  • @NaveenTamrakar: Could you please elaborate? –  Oct 28 '14 at 08:08
  • @NaveenTamrakar - 8 MB is not at all too big for an apk file. Google requires you to limit apk files to 50 MB. The size of the apk is not causing this problem. – Ted Hopp Oct 28 '14 at 08:08
  • I suggest using the memory analysis tools that Android provides. See [this documentation](http://developer.android.com/tools/debugging/debugging-memory.html) for how to analyze your app's memory usage. – Ted Hopp Oct 28 '14 at 08:11
  • i know that google apk limit is 50 mb but have memory in your device such as small phone have 256 mb Ram so we can run 25mb apk in thia device – Naveen Tamrakar Oct 28 '14 at 08:12
  • I've updated my question with info on what device I've seen the crash happen (Samsung Galaxy S3 with 1 GB RAM) –  Oct 28 '14 at 08:20
  • @TedHopp - Thanks Ted, I've been looking into that. I get the same outOfMemoryError on the emulator. Heap size, Allocated, Free, %Used, #Objects 58.945 MB 57.257 MB 1.688 MB 97.14% 48,294 I am not allowed to use more than 57 MB? –  Oct 28 '14 at 09:06
  • That's not surprising. The maximum heap size varies considerably across API versions, but can be as low as 16 MB on some devices. It can also be further constrained by device manufacturers. See [this thread](http://stackoverflow.com/questions/18675557/what-is-the-maximum-amount-of-ram-an-app-can-use) (among many on this topic). You can use [`ActivityManager.getMemoryClass()`](http://developer.android.com/reference/android/app/ActivityManager.html#getMemoryClass%28%29) to determine the memory limits at run time. You can use `android:largeHeap="true"` in the manifest to increase it. – Ted Hopp Oct 28 '14 at 14:14
  • Thanks @TedHopp - Using the device monitor I managed to figure out what was using all this memory and got it down to max 23 MB which seems to rum fine during all my tests. –  Oct 28 '14 at 14:21

2 Answers2

1

Yes, drawables are shared between UI elements, according to this old article on Android Developers Blog: Drawable mutations

I cite from it:

However, all these drawables share a common state, called the "constant state." The content of this state varies according to the type of drawable you are using, but it usually contains all the properties that can be defined by a resource. In the case of a button, the constant state contains a bitmap image. This way, all buttons across all applications share the same bitmap, which saves a lot of memory.

Bazzilla
  • 76
  • 1
  • 4
0

Yes. Resourced are shared and not duplicated.