Утечка памяти при использовании ListView в Android - PullRequest
1 голос
/ 22 октября 2010

Я борюсь с утечкой памяти, связанной с 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;
    }
}

1 Ответ

1 голос
/ 22 октября 2010

Ваши GListView объекты собираются для мусора.По крайней мере, они вызываются с finalize(), когда GC выполняется вручную из DDMS.К сожалению, файл DDMS HPROF кажется несовместимым с моей версией jhat, и я не являюсь пользователем Eclipse, поэтому у меня нет свободного доступа к MAT.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...