3

I have a quite simple activity like this :

public class SurvivalActivity extends Activity {
    private static final String KEY_LAYOUT_ID = "SurvivalLayoutId";
    int mLayoutId;
    private static final int[] mSurvivalLayouts = {
        R.layout.survival1,
        R.layout.survival2,
        R.layout.survival3,
    };

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final Intent i = getIntent();
        if (savedInstanceState != null && savedInstanceState.containsKey(KEY_LAYOUT_ID)) {
            mLayoutId = savedInstanceState.getInt(KEY_LAYOUT_ID, 0);
        } else if (i != null) {
            mLayoutId = i.getIntExtra(KEY_LAYOUT_ID, 0);
        } else {
            mLayoutId = 0;
        }

        // Layout
        setContentView(mSurvivalLayouts[mLayoutId]);

        // Title
        Util.setTitleFont(this, findViewById(R.id.title));

        // "Next" button
        final View nextButton = findViewById(R.id.survival_next);
        Util.setFont(this, nextButton, "Lobster.ttf");
        nextButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(final View v) {
                final Intent next = new Intent(SurvivalActivity.this, SurvivalActivity.class);
                next.putExtra(KEY_LAYOUT_ID, (mLayoutId + 1) % mSurvivalLayouts.length);
                startActivity(next);
                finish();
            }
        });
    }

    @Override
    protected void onSaveInstanceState(final Bundle outState) {
        outState.putInt(KEY_LAYOUT_ID, mLayoutId);
    }
}

The two Util.* static methods just change the font of the TextView.

All 3 layouts are rather simple, let me show you the first :

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            style="@style/Title"
            android:text="@string/surv1_title" />

        <TextView
            style="@style/Content"
            android:text="@string/surv1_1" />

        <ImageView
            style="@style/Picture"
            android:src="@drawable/surv_crafting" />
        <TextView
            style="@style/PicLegend"
            android:src="@string/surv_crafting_leg" />
        <ImageView
            style="@style/Picture"
            android:src="@drawable/surv_hache" />
        <TextView
            style="@style/PicLegend"
            android:src="@string/surv_hache_leg" />
        <ImageView
            style="@style/Picture"
            android:src="@drawable/surv_pioche" />
        <TextView
            style="@style/PicLegend"
            android:src="@string/surv_pioche_leg" />

        <TextView
            style="@style/Content"
            android:text="@string/surv1_2" />

        <ImageView
            style="@style/Picture"
            android:src="@drawable/surv_charbon" />
        <TextView
            style="@style/PicLegend"
            android:src="@string/surv_charbon_leg" />

        <TextView
            style="@style/Content"
            android:text="@string/surv1_3" />

        <ImageView
            style="@style/Picture"
            android:src="@drawable/surv_torch" />
        <TextView
            style="@style/PicLegend"
            android:src="@string/surv_torch_leg" />

        <TextView
            style="@style/Content"
            android:text="@string/surv1_4" />

        <ImageView
            style="@style/Picture"
            android:src="@drawable/surv_abri" />
        <TextView
            style="@style/PicLegend"
            android:src="@string/surv_abri_leg" />

        <TextView
            style="@style/Content"
            android:text="@string/surv1_5" />

        <Button
            style="@style/SurvivalBoxNext"
            android:text="@string/surv1_next" />

    </LinearLayout>
</ScrollView>

As you can see it's just several TextViews with ImageViews, and a Button that triggers the load of the next activity.

I launch the app, it displays the first screen. I scroll down to the button, click, the second screen is displayed (with a hiccup). I scroll down to the button, click, and boom.

03-02 16:36:46.488 E/AndroidRuntime(10611): java.lang.RuntimeException: Unable to start activity ComponentInfo{net.bicou.myapp/net.bicou.myapp.SurvivalActivity}: android.view.InflateException: Binary XML file line #72: Error inflating class <unknown>
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1955)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1980)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.app.ActivityThread.access$600(ActivityThread.java:122)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1146)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.os.Handler.dispatchMessage(Handler.java:99)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.os.Looper.loop(Looper.java:137)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.app.ActivityThread.main(ActivityThread.java:4340)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at java.lang.reflect.Method.invokeNative(Native Method)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at java.lang.reflect.Method.invoke(Method.java:511)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at dalvik.system.NativeStart.main(Native Method)
03-02 16:36:46.488 E/AndroidRuntime(10611): Caused by: android.view.InflateException: Binary XML file line #72: Error inflating class <unknown>
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.view.LayoutInflater.createView(LayoutInflater.java:606)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.view.LayoutInflater.onCreateView(LayoutInflater.java:653)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:678)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:739)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:742)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:251)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.app.Activity.setContentView(Activity.java:1835)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at net.bicou.myapp.SurvivalActivity.onCreate(SurvivalActivity.java:34)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.app.Activity.performCreate(Activity.java:4465)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1919)
03-02 16:36:46.488 E/AndroidRuntime(10611):     ... 11 more
03-02 16:36:46.488 E/AndroidRuntime(10611): Caused by: java.lang.reflect.InvocationTargetException
03-02 16:36:46.488 E/AndroidRuntime(10611):     at java.lang.reflect.Constructor.constructNative(Native Method)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.view.LayoutInflater.createView(LayoutInflater.java:586)
03-02 16:36:46.488 E/AndroidRuntime(10611):     ... 25 more
03-02 16:36:46.488 E/AndroidRuntime(10611): Caused by: java.lang.OutOfMemoryError
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.graphics.Bitmap.nativeCreate(Native Method)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.graphics.Bitmap.createBitmap(Bitmap.java:605)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.graphics.Bitmap.createBitmap(Bitmap.java:551)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:437)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:524)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:499)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:351)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:773)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.content.res.Resources.loadDrawable(Resources.java:1937)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.content.res.TypedArray.getDrawable(TypedArray.java:601)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.widget.ImageView.<init>(ImageView.java:119)
03-02 16:36:46.488 E/AndroidRuntime(10611):     at android.widget.ImageView.<init>(ImageView.java:109)
03-02 16:36:46.488 E/AndroidRuntime(10611):     ... 28 more
03-02 16:36:46.520 W/ActivityManager(  211):   Force finishing activity net.bicou.myapp/.SurvivalActivity

I don't understand :

  1. Why the previous activities are not freed to free up some space
  2. Why is my app taking up so much heap (Grow heap (frag case) to 60.869MB for 3600016-byte allocation)
  3. How can I do to display successively 3 activities containing each about 10 TextViews and 10 ImageViews
  4. If I did something wrong, because I can't see anything wrong in my code, but there is obviously something wrong.

Thank you.

Edit: picture sizes of the first activity:

-rw-r--r--  1 bicou  staff   167197 29 fév 16:42 surv_abri.jpg 600x377 px
-rw-r--r--  1 bicou  staff    24658 29 fév 16:42 surv_charbon.png 559x277 px
-rw-r--r--  1 bicou  staff     5285 29 fév 16:42 surv_crafting.png 214x121 px
-rw-r--r--  1 bicou  staff     4190 29 fév 16:42 surv_hache.png 214x121 px
-rw-r--r--  1 bicou  staff     3809 29 fév 16:42 surv_pioche.png 214x121 px
-rw-r--r--  1 bicou  staff     2252 29 fév 16:42 surv_torch.png 215x121 px

Second activity:

-rw-r--r--  1 bicou  staff     3371 29 fév 16:42 surv_four.png 204x112 px
-rw-r--r--  1 bicou  staff     5059 29 fév 16:42 surv_glass.png 215x122 px
-rw-r--r--  1 bicou  staff     3176 29 fév 16:42 surv_malle.png 204x112 px
-rw-r--r--  1 bicou  staff     2676 29 fév 16:42 surv_pelle.png 204x112 px
-rw-r--r--  1 bicou  staff   167166 29 fév 16:42 surv_repere.png 528x331 px
-rw-r--r--  1 bicou  staff   134706 29 fév 16:42 surv_sand.jpg 854x480 px

Third activity (crashing):

-rw-r--r--  1 bicou  staff    58919 29 fév 16:42 surv_1.jpg 600x377 px
-rw-r--r--  1 bicou  staff    51144 29 fév 16:42 surv_2.jpg 600x377 px
-rw-r--r--  1 bicou  staff    46917 29 fév 16:42 surv_3.jpg 600x377 px
-rw-r--r--  1 bicou  staff    53226 29 fév 16:42 surv_4.jpg 600x377 px
-rw-r--r--  1 bicou  staff    37787 29 fév 16:42 surv_5.jpg 600x377 px
-rw-r--r--  1 bicou  staff    31050 29 fév 16:42 surv_6.jpg 600x377 px
-rw-r--r--  1 bicou  staff    38389 29 fév 16:42 surv_7.jpg 600x377 px
-rw-r--r--  1 bicou  staff    44471 29 fév 16:42 surv_8.jpg 600x377 px

And the Window background:

-rw-r--r--  1 bicou  staff    30857 29 fév 16:42 background_img.png

EDIT:

OK — I tried inflating the views directly from code in order to see if I had a buggy image. Here's my activity code (only variables + onCreate as the rest is identical)

private static final int[] mTitles = {
    R.string.surv1_title, R.string.surv2_title, R.string.surv3_title
};
private static final int[][] mTextViews = {
    {   R.string.surv1_1, R.string.surv1_2, R.string.surv1_3, R.string.surv1_4, R.string.surv1_5 },
    {   R.string.surv2_1, R.string.surv2_2, R.string.surv2_3, R.string.surv2_4, R.string.surv2_5, R.string.surv2_6 },
    {   R.string.surv3_1, R.string.surv3_2, R.string.surv3_3 }
};
private static final int[][] mImageViews = {
    {   R.drawable.surv_pioche, R.drawable.surv_crafting, R.drawable.surv_hache, R.drawable.surv_charbon,
        R.drawable.surv_torch, R.drawable.surv_abri },
    {   R.drawable.surv_malle, R.drawable.surv_four, R.drawable.surv_pelle, R.drawable.surv_repere,
        R.drawable.surv_sand, R.drawable.surv_glass },
    {   R.drawable.surv_1, R.drawable.surv_2, R.drawable.surv_3, R.drawable.surv_4,
        R.drawable.surv_5, R.drawable.surv_6, R.drawable.surv_7, R.drawable.surv_8  },
};
private static final int[] mNextButtons = {
    R.string.surv1_next, R.string.surv2_next, R.string.surv3_next
};

@Override
public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    final Intent i = getIntent();
    if (savedInstanceState != null && savedInstanceState.containsKey(KEY_LAYOUT_ID)) {
        mLayoutId = savedInstanceState.getInt(KEY_LAYOUT_ID, 0);
    } else if (i != null) {
        mLayoutId = i.getIntExtra(KEY_LAYOUT_ID, 0);
    } else {
        mLayoutId = 0;
    }

    // Layout
    //setContentView(mSurvivalLayouts[mLayoutId]);
    LinearLayout ll;
    ScrollView sv;
    TextView tv;
    ImageView iv;
    Button b;

    sv = new ScrollView(this);
    sv.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
    ll = new LinearLayout(this);
    ll.setOrientation(LinearLayout.VERTICAL);
    ll.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

    tv = new TextView(this);
    tv.setId(R.id.title);
    tv.setText(getString(mTitles[mLayoutId]));
    ll.addView(tv);

    for (final int textId: mTextViews[mLayoutId]) {
        tv = new TextView(this);
        tv.setText(getString(textId));
        ll.addView(tv);
    }

    for (final int imgId: mImageViews[mLayoutId]) {
        L.i("Creating image: "+imgId);
        iv = new ImageView(this);
        iv.setImageResource(imgId);
        ll.addView(iv);
    }

    b = new Button(this);
    b.setText(getString(mNextButtons[mLayoutId]));
    b.setId(R.id.survival_next);
    ll.addView(b);

    sv.addView(ll);
    setContentView(sv);

    // Title
    Util.setTitleFont(this, findViewById(R.id.title));

    // "Next" button
    final View nextButton = findViewById(R.id.survival_next);
    Util.setFont(this, nextButton, "Lobster.ttf");
    nextButton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(final View v) {
            final Intent next = new Intent(SurvivalActivity.this, SurvivalActivity.class);
            next.putExtra(KEY_LAYOUT_ID, (mLayoutId + 1) % mSurvivalLayouts.length);
            startActivity(next);
            finish();
        }
    });
}

As you can see I am just inflating the views directly, and L.i (which is an alias to Log.i(TAG, ...)) indicates what was the last ImageView inflated before any crash.

I ran the app, saw the 1st activity, then the second, and as previously it crashes while loading the third one. The last ID I saw in the logcat was the last picture R.drawable.surv_8. This is a 630x377 jpeg file, 45 kiB.

I tried to change the order of the views like this:

private static final int[][] mImageViews = {
    {   R.drawable.surv_pioche, R.drawable.surv_crafting, R.drawable.surv_hache, R.drawable.surv_charbon,
        R.drawable.surv_torch, R.drawable.surv_abri },
    {   R.drawable.surv_malle, R.drawable.surv_four, R.drawable.surv_pelle, R.drawable.surv_repere,
        R.drawable.surv_sand, R.drawable.surv_glass },
    {   R.drawable.surv_8, R.drawable.surv_1, R.drawable.surv_2, R.drawable.surv_3, R.drawable.surv_4,
        R.drawable.surv_5, R.drawable.surv_6, R.drawable.surv_7,  },
};

So that surv_8 is first. The app is still crashing at the last picture, which is R.drawable.surv_7. So that is not an image issue.

Then I removed one of the pictures out of mImageViews[2] so that I have only 7 pictures instead of 8. The app is working as expected: the activity loads, when I click the button I go to the next one, and on the last I go to the first. No crash.

I can however tell that the activity 1 and 2 stay into memory. Indeed, have a look at the timings:

03-04 15:47:13.685 I/ActivityManager(17430): Displayed net.bicou.myapp/.SurvivalActivity: +2s570ms
03-04 15:47:36.834 I/ActivityManager(17430): Displayed net.bicou.myapp/.SurvivalActivity: +803ms
03-04 15:47:39.756 I/ActivityManager(17430): Displayed net.bicou.myapp/.SurvivalActivity: +1s476ms
03-04 15:47:44.201 I/ActivityManager(17430): Displayed net.bicou.myapp/.SurvivalActivity: +462ms
03-04 15:47:46.717 I/ActivityManager(17430): Displayed net.bicou.myapp/.SurvivalActivity: +474ms
03-04 15:47:48.599 I/ActivityManager(17430): Displayed net.bicou.myapp/.SurvivalActivity: +474ms

400ms instead of 1.5-2.5 sec to load the activity.

Why is this staying into memory?

=> ** Do I need to manually free all pictures upon onDestroy() ? **

=> What do you think about this: http://androidactivity.wordpress.com/2011/09/24/solution-for-outofmemoryerror-bitmap-size-exceeds-vm-budget/
With this solution I could load like 10 bitmaps globally, and I would free some while loading another activity?

Benoit Duffez
  • 11,839
  • 12
  • 77
  • 125
  • I strongly suspect it is because of image sizes. – kosa Mar 02 '12 at 16:16
  • See my edit. They are not so big. – Benoit Duffez Mar 02 '12 at 16:21
  • 2
    @Bicou Filesize is not too relevant since both jpg and png are compressed image formats. Which resolution do your images have? That's what matters because they get stored uncompressed in memory. *(e.g. you can compress a 10000x10000 px single color image pretty well, but in memory it will get huge nontheless)* –  Mar 02 '12 at 16:28
  • @alextsc: Good point. Let met edit my post. – Benoit Duffez Mar 02 '12 at 16:35

3 Answers3

5

I'm sorry that the answer of this question wasn't actually possible to have with the elements I gave in my question.

Indeed, as mentioned in another question here: Why are all my bitmaps upsampled 200%?, I put my pictures in the drawable folder, which, on a xhdpi screen like mine, will cause Android to upsample everything twice (to match xhdpi against mdpi), and will result in a 400% memory usage (twice the width and twice the height so 4 times as many pixels).

One more thing, since I don't want the user to be able to go back (see the finish() right after the startActivity()), here's what I put in the onPause():

private void unbindDrawables(View view) {
    if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
    }
    if (view instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
        }
        ((ViewGroup) view).removeAllViews();
    }
}

This is some code I got here on StackOverflow (for example here: Drawable vs Single reusable Bitmap better with memory?).

Here are my remarks about this code and why every line is important:

  • The setCallback(null) removes the reference to the activity, so that it can be garbage collected. If you don't do this, all the views will stay in memory.
  • You also need to call it from onPause, because onDestroy is not guaranteed to be called.
  • You may need to cause a garbage collection after this, in order to help the GC understand that some references to objects that were made orphans and that can be GC'd. Just call System.gc().

This is the resulting onPause code, with the main layout of your activity having the id top_layout:

@Override
protected void onPause() {
    super.onPause();
    unbindDrawables(findViewById(R.id.top_layout));
    System.gc();
}
Community
  • 1
  • 1
Benoit Duffez
  • 11,839
  • 12
  • 77
  • 125
  • +1 for the first part of the answer. But as per second part of your answer when i call the unbidDrawables() method from onpause, and press the home key to trigger onPause method then launch the app again , my activity is all blank and then it crashes.. – Vinay Jun 10 '14 at 13:06
  • 1
    My app was displaying some kind of 1-2-3 tutorial, so when you leave page 1, it's gone. This is not your use case, so you shouldn't do the same. – Benoit Duffez Jun 11 '14 at 06:35
2

It might just be that the bitmap you're putting in the ImageView is very large. Here's some things you can try:

Ditch the xml layout and just inflate and display the problematic ImageView or ImageViews and see if this way you're getting the error.

Also check each of your images to see what size they actually have. The size they'll take in memory is roughly 4*width*height (in bytes, where width and height are the image's size in pixels).

Since your Bitmap instances are taking up memory on the heap, I'm imagining you're using Android 3 or above. In these versions that's where Bitmap instances go (just like any other Java instance). In Android 2.x and below, Bitmap instances were allocated in some offheap memory. Knowing this, make sure that that high heap usage you're getting is indeed from the images, and not from some other instances that are created a lot. Try debugging your constructors and see who calls what when the app starts/runs.

As per Bicou's observations, you might want to manually load your images via BitmapFactory, and in doing so maybe downsample them (via the Options object). Also, try keeping a counter of how much image bytes in memory you total by incrementing with 4*width*height of each image you're actually loading into a Bitmap Object.

Shivan Dragon
  • 15,004
  • 9
  • 62
  • 103
  • 2
    Scroll down to the bottom of the stack trace, you'll see it is actually an `OutOfMemoryError` thrown while trying to allocate memory for a bitmap. – Benoit Duffez Mar 02 '12 at 16:25
  • Right you are, sorry, I didn't see it until I actually CTRL-F-ed the word in the web page. Sorry. I'm gonna update my answer. – Shivan Dragon Mar 02 '12 at 20:06
  • 1
    @AndreiBodnarescu that statement is not entirely true. It is correct to say that `Bitmap` is not allocated on the same heap prior to Android 3, but it is still accounted against that heap so any numbers seen in logcat growing the heap size do in fact reflect allocated `Bitmap` objects. – devunwired Mar 02 '12 at 20:27
  • Yes you're right, I was talking of the Java heap. The actual Linux process heap does reflect Bitmap instances. – Shivan Dragon Mar 02 '12 at 20:30
  • 1
    @Bicou Apart from my previous comment, +1 because this answer is mostly correct. Your 600x377 images will amount to just under 1MB each when inflated into memory. Take into account that the images from each previous Activity is also in memory because those Activities are **PAUSED** and not garbage collected so the user can return to them. You will need to downsample your images before loading them into memory (`BitmapFactory` helps with this) or recycle images on the same Activity instead of stacking multiples. – devunwired Mar 02 '12 at 20:31
  • Yeah but the activities are finish()'d as soon as another one is started... so I assumed that they were GC'd – Benoit Duffez Mar 02 '12 at 23:22
  • @AndreiBodnarescu: please, could you have a look at my edit from my question? I tried another way as you suggested. Thank you very much for your support. – Benoit Duffez Mar 04 '12 at 14:53
  • Well, to answer your question: you should call bitmap.destoy() and bitmap = null (maybe a System.gc() as well) when your activity is destroyed or even paused. Then you make sure that all images are re-initied upon action start/resume. – Shivan Dragon Mar 05 '12 at 08:56
  • I tried to `removeAllViews()`, to put all references to `null`, call `System.gc()` (which freed 13MB by the way), but it is still crashing on the third activity. I cannot call `bitmap.destroy()` because I don't hold any reference to any `Bitmap`. I only have `TextView`s and `ImageView`s. I don't want the user to be able to go back to the previous activity. I just want him to be able to loop the contents like 1-2-3-1-2-3-1... etc. – Benoit Duffez Mar 05 '12 at 22:56
1

The best way to optimize memory usage with bitmaps in your case is to save a list of your ImageViews make this before call finish() for every ImageView:

((BitmapDrawable) myImageView.getDrawable()).getBitmap().recycle();
myImageView = null;
sgallego
  • 318
  • 3
  • 15