1

I have an activity which does this:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.list);

    ListView lv = (ListView) findViewById(R.id.ListList);
    lv.setItemsCanFocus(true);
    lv.setOnItemClickListener(this);
    adapter = new ListAdapter(this, lv, model, R.layout.simple, this);
    lv.setAdapter(adapter);
}

My list adapter class looks like this.

public static class ListAdapter extends ArrayAdapter<ListItem>
public ListAdapter(Activity activity, ListView lv, List<ListItem> model, int resource, OnActionClickListener onActionClickListener) {
    super(activity, android.R.layout.simple_list_item_1, model);
    ....
}

If I do a orientation change, about 20 times, it will run out of memory and give me an error like this:

12-22 17:33:44.977: E/dalvikvm-heap(29145): 1536000-byte external allocation too large for this process.

If I don't setup the rest of the code in onCreate (past setContentView), I don't have an issue.

I'm guessing I'm holding on (inadvertantly) to an instance of the activity, but I'm not sure how.

Any ideas?

tia.


So the thing that is causing the problem is "lv.setAdapter(adapter);" -- if I comment out that line, I don't have the issue... I tried lv.setAdapter(null) in onDestroy() - didn't help. I also added this (http://stackoverflow.com/questions/1147172/what-android-tools-and-methods-work-best-to-find-memory-resource-leaks) to onDestroy() as well - nothing seems to help.


So, I've narrowed it down as small as I can go.

Here is the main TestAppActivity.java file.

package com.junk.test;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class TestAppActivity extends Activity {
    protected ArrayList<ListItem> model = new ArrayList<ListItem>();
    protected ListAdapter adapter = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        ListView lv = (ListView) findViewById(R.id.ListList);
        lv.setItemsCanFocus(true);
        adapter = new ListAdapter(this, lv, model);
        lv.setAdapter(adapter);

        if (savedInstanceState == null) {
            Log.i("test", "@@ start");
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        boolean change = true;
                        Thread.sleep(4 * 1000);
                        for (int ii = 0; ii < 200; ii++) {
                            setRequestedOrientation(change ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                            Thread.sleep(4 * 1000);
                            change = !change;
                            Log.i("test", "@@ change: " + (ii+1));
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        Log.i("test", "@@ complete!");
                    }
                }
            }).start();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

// doesn't make any difference.
//        ListView lv = (ListView) findViewById(R.id.ListList);
//        lv.setAdapter(null);
//        adapter.clear();
//        adapter = null;

        unbindDrawables(findViewById(R.id.ListList));
        System.gc();
    }

    private void unbindDrawables(View view) {
        if (view == null) { return; }

        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));
            }
            if (view instanceof AdapterView) {

            } else {
                ((ViewGroup) view).removeAllViews();
            }
        }
    }

    public static class ListItem {
        public int x;
    }

    public static class ListAdapter extends ArrayAdapter<ListItem> implements View.OnClickListener {
        public ListAdapter(Activity activity, ListView lv, List<ListItem> model) {
            super(activity.getApplicationContext(), android.R.layout.simple_list_item_1, model);
        }

        @Override
        public void onClick(View v) {
        }
    }
}

And here is main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:background="@drawable/player_background">

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

    <ListView
        android:id="@+id/ListList"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:choiceMode="singleChoice"
        android:cacheColorHint="#00000000"
        android:dividerHeight="3dp"
        android:overScrollFooter="@null" />

</LinearLayout>

And it is STILL leaking - takes like 110 or so orientation changes, but eventually it gives an allocation error!

Kara
  • 6,115
  • 16
  • 50
  • 57
user645402
  • 737
  • 1
  • 16
  • 34
  • How many items are in your list? – Reed Dec 23 '11 at 02:09
  • Does the issue occur with no ListView in your layout? You need to start chipping out things until you narrow it down. – Steven Dec 23 '11 at 03:45
  • without the listview, the error doesn't occur. specifically, if i don't set the adapter on the list view lv.setAdapter( adapter ); then i don't see it either. – user645402 Dec 23 '11 at 05:33
  • Argh!!! Answers here!
    http://stackoverflow.com/questions/3910473/i-have-a-memory-leak-using-listactivity-in-android/6530551#6530551
    http://stackoverflow.com/questions/3997993/memory-lead-when-using-listview-in-android
    – user645402 Jan 06 '12 at 17:33
  • Argh!!! Answers here! http://stackoverflow.com/questions/3910473/i-have-a-memory-leak-using-listactivity-in-android/6530551#6530551 http://stackoverflow.com/questions/3997993/memory-lead-when-using-listview-in-android – user645402 Jan 06 '12 at 17:34

2 Answers2

0

Eclipse Memory Analizer Tool can help you to find the root cause. The usual scenario is to take heap dump right after application start, then do several orientation changes, force GC with DDMS and then take another heap dump. After that you can compare heap dumps and see if there are leftover activities or something. "Path to GC root" tool can show a missing reference that prevents leftover objects from being collected.

Check this question for more references about MAT.

Community
  • 1
  • 1
Darth Beleg
  • 2,657
  • 24
  • 26
0

Which launch mode are you using for your activity ?

Maybe these links will help you decide

Launch modes 1

Launch modes 2

I hope it helps...

R.daneel.olivaw
  • 2,681
  • 21
  • 31