Я борюсь с утечкой памяти, связанной с ListView.Я создал следующую маленькую программу, которая демонстрирует это поведение.
Я создаю 2 LinearLayouts.Первый имеет кнопку и элемент управления GListView.Код для GListView приведен ниже, но он просто подклассов ListView и реализует интерфейс ListAdapter.Когда GListView создан, он устанавливает свой адаптер для себя.
Теперь, когда вы нажимаете кнопку, я переключаюсь на второй LinearLayout.Этот макет имеет только одну кнопку.Когда вы нажимаете эту кнопку, я создаю новый 1-й макет с новым GListView и устанавливаю его в качестве активного вида.
Запустите программу и переключайтесь между двумя видами 20 раз.Затем вызовите DDMS и форсируйте сборку мусора.Затем создайте дамп памяти и используйте анализатор памяти, и вы обнаружите 21 оставшийся объект GListView.То есть 20 GListViews, которые больше не связаны ни с чем, НЕ были освобождены.
Если я сделаю дамп памяти и посмотрю на один из GListView, который должен был быть переработан, и перечислю входящие ссылкииспользуя анализатор памяти, я получаю следующее:
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
-------------------------------------------------------------------------------------------------------
Теперь, если я закомментирую функцию setAdapter (this) в конструкторе GListView и повторю вышеизложенное, я обнаружу, что существует только 1 GListView, которыйостается.То есть в этом случае все неиспользуемые GListView были правильно переработаны.
Кто-то предложил мне создать закрытый класс в моем GListView для обработки интерфейса ListAdapter, и я попробовал это, но это не помогло.,Я также попытался создать совершенно отдельный открытый класс для обработки ListAdapter, но, увы, это тоже не сработало.
Конечно, есть какой-то способ заставить эти объекты исчезнуть, когда они больше нигде не используются.(Разве не в этом вся суть сбора мусора?)
Буду признателен за любую помощь.Я действительно тяну свои волосы на этом.
Спасибо.
/*
* 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;
}
}