Memory leak when using ListView in Android

I am struggling with a memory leak related to ListView. I created the following small program that demonstrates this behavior.

I am creating 2 LinearLayouts. The first has a button and a GListView control. The code for GListView is below, but it is just a subclass of ListView and implements the ListAdapter interface. When the GListView is created, it installs the adapter itself.

Now when you click the button, I switch to the second LinearLayout. This layout has only one button. When you click this button, I create a new 1st layout with a new GListView and set it as the active view.

Run the program and go between the two views 20 times. Then pick up DDMS and force garbage collection. Then unload the memory and use the memory analyzer, and you will find 21 GListView objects. That is, 20 GListViews that are no longer associated with anything were NOT released.

If I dump the memory and look at one of the GListView that should have been redesigned and list the incoming links using the Memory Analyzer, I get the following:

Class Name | Shallow Heap | Retained Heap ------------------------------------------------------------------------------------------------------- com.gabysoft.memoryleak.GListView @ 0x43e72270 Unknown | 672 | 3,528 |- host android.view.View$ScrollabilityCache @ 0x43e72560 | 80 | 584 |- this$0 android.widget.AbsListView$RecycleBin @ 0x43e72830 | 40 | 160 |- mCallback android.graphics.drawable.StateListDrawable @ 0x43e728a8 | 64 | 1,464 |- this$0 android.widget.AdapterView$AdapterDataSetObserver @ 0x43e730b8| 16 | 16 ------------------------------------------------------------------------------------------------------- 

Now, if I comment on the setAdapter (this) 'function in the GListView constructor and repeat above, I find that there is only 1 GListView left. That is, in this case, all unused GListViews were correctly recycled.

Someone suggested creating a private class in my GListView to handle the ListAdapter interface, and I tried this, but that didn't help. I also tried to create a completely separate public class to handle the ListAdapter, but alas, this does not work either.

Of course, there is some way to remove these objects when they are not used anywhere else. (Isn't that what garbage collection is?)

Any help would be greatly appreciated. I really pull my hair on it.

Thanks.

 /* * Activity */ package com.gabysoft.memoryleak; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ListView; public class MemoryLeak extends Activity implements android.view.View.OnClickListener { LinearLayout ll2; boolean page2 = false; private LinearLayout CreateLayout() { LinearLayout ll = new LinearLayout(this); Button btn1 = new Button(this); ListView lv = new GListView(this); btn1.setText("Press"); btn1.setLayoutParams(new LinearLayout.LayoutParams(100, 40)); btn1.setOnClickListener(this); ll.addView(btn1); ll.addView(lv); return(ll); } /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); CreateLayout(); LinearLayout ll = CreateLayout(); ll2 = new LinearLayout(this); Button btn2 = new Button(this); btn2.setText("Back"); btn2.setLayoutParams(new LinearLayout.LayoutParams(100, 40)); btn2.setOnClickListener(this); ll2.addView(btn2); setContentView(ll); } @Override public void onClick(View v) { if (page2) { LinearLayout ll = CreateLayout(); setContentView(ll); page2 = false; } else { setContentView(ll2); page2 = true; } } } /* * GListView */ package com.gabysoft.memoryleak; import android.content.Context; import android.database.DataSetObserver; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.TextView; public class GListView extends ListView implements ListAdapter { Context m_context; DataSetObserver m_observer = null; public GListView(Context context) { super(context); m_context = context; setAdapter(this); setChoiceMode(CHOICE_MODE_SINGLE); } /* * ListAdapter */ @Override public boolean areAllItemsEnabled() { return true; } @Override public boolean isEnabled(int position) { return true; } @Override public int getCount() { return(0); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return(position); } @Override public int getItemViewType(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { TextView tv = new TextView(m_context); tv.setText("Item"); return(tv); } @Override public int getViewTypeCount() { return 1; } @Override public boolean hasStableIds() { return false; } @Override public boolean isEmpty() { return false; } @Override public void registerDataSetObserver(DataSetObserver observer) { m_observer = observer; } @Override public void unregisterDataSetObserver(DataSetObserver observer) { m_observer = null; } } 
+1
source share
1 answer

GListView objects are garbage collected. At best, they are called using finalize() when a manual GC is executed from DDMS. Unfortunately, the HPROF DDSS file seems incompatible with my version of jhat , and I am not an Eclipse user, so I do not have open access to MAT.

+1
source

Source: https://habr.com/ru/post/905135/


All Articles