当Android中使用的ListView内存铅 [英] Memory lead when using ListView in Android

查看:235
本文介绍了当Android中使用的ListView内存铅的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我挣扎与一个ListView相关联的内存泄漏。我创建了下面的小程序,它表现出这种行为。

我要做的就是创建2个LinearLayouts。首先有一个按钮和一个GListView控制。在$ C $下GListView低于,但它只是子类ListView控件,并实现了ListAdapter接口。当创建GListView,它设置它的适配器本身。

现在,当你preSS的按钮,我切换到第二个的LinearLayout。此布局只有一个按钮。当你preSS这个按钮,创建一个新的第一布局新GListView并将其设置为活动视图。

运行程序,和20次的两个视图之间切换。然后调出DDMS并强制进行垃圾回收。然后转储内存,并使用内存分析器,你会发现剩下的21 GListView对象。也就是说,20 GListViews未再连接到任何尚未被释放。

如果我做了内存转储,并看一看应该已经回收了GListViews之一,并列出使用Memory Analyzer中进来的参考,我得到如下:

 类名称|浅堆|保留堆
-------------------------------------------------------------------------------------------------------
com.gabysoft.memoryleak.GListView @ 0x43e72270未知| 672 | 3528
|  - 主机android.view.View $ ScrollabilityCache @ 0x43e72560 | 80 | 584
|  - 这$ 0个android.widget.AbsListView $ RECYCLEBIN @ 0x43e72830 | 40 | 160
|  -  mCallback android.graphics.drawable.StateListDrawable @ 0x43e728a8 | 64 | 1464
|  - 这$ 0个android.widget.AdapterView $ AdapterDataSetObserver @ 0x43e730b8 | 16 | 16
-------------------------------------------------------------------------------------------------------
 

现在,如果我注释掉setAdapter(本)中的GListView构造函数,并重复上述,我觉得是有剩下的只有1 GListView。也就是说,在这种情况下,所有的未使用的GListViews的已适当地循环利用。

有人建议我我GListView处理ListAdapter界面内创建一个私有类的,我试过了,但它并没有帮助。我也试图建立一个完全独立的公共类来处理ListAdapter,但是,唉,这似乎并没有擦出火花。

当然,有一些方法,以使这些对象消失,当他们不再在任何地方使用。 (这不就是垃圾回收是怎么一回事?)

任何帮助将是AP preciated。我真的很拉我的头发就这一个。

感谢。

  / *
 * 活动
 * /

包com.gabysoft.memoryleak;

进口android.app.Activity;
进口android.os.Bundle;
进口android.view.View;
进口android.widget.Button;
进口android.widget.LinearLayout;
进口android.widget.ListView;

公共类MemoryLeak扩展活动实现android.view.View.OnClickListener
{
    的LinearLayout [112;
    布尔第2页= FALSE;

    私人的LinearLayout CreateLayout()
    {
        的LinearLayout LL =新的LinearLayout(本);

        按钮BTN1 =新的按钮(这一点);
        ListView的LV =新GListView(本);

        btn1.setText(preSS);
        btn1.setLayoutParams(新LinearLayout.LayoutParams(100,40));
        btn1.setOnClickListener(本);

        ll.addView(BTN1);
        ll.addView(LV);

        返回(LL);
    }

    / **第一次创建活动时调用。 * /
    @覆盖
    公共无效的onCreate(包savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        CreateLayout();

        的LinearLayout LL = CreateLayout();
        [112 =新的LinearLayout(本);

        按钮BTN2 =新的按钮(这一点);

        btn2.setText(返回);
        btn2.setLayoutParams(新LinearLayout.LayoutParams(100,40));
        btn2.setOnClickListener(本);

        ll2.addView(BTN2);

        的setContentView(Ⅱ);
    }

    @覆盖
    公共无效的onClick(视图v)
    {
        如果(第2页)
        {
            的LinearLayout LL = CreateLayout();

            的setContentView(Ⅱ);

            第2页= FALSE;
        }
        其他
        {
            的setContentView(LL2);
            第2页= TRUE;
        }
    }

}

/ *
 * GListView
 * /
包com.gabysoft.memoryleak;

进口android.content.Context;
进口android.database.DataSetObserver;
进口android.view.View;
进口android.view.ViewGroup;
进口android.widget.AdapterView;
进口android.widget.ListAdapter;
进口android.widget.ListView;
进口android.widget.TextView;

公共类GListView扩展的ListView工具ListAdapter
{
    语境m_context;
    DataSetObserver m_observer = NULL;

    公共GListView(上下文的背景下)
    {
        超(上下文);

        m_context =背景;

        setAdapter(本);

        setChoiceMode(CHOICE_MODE_SINGLE);
    }

    / *
     * ListAdapter
     * /


    @覆盖
    公共布尔areAllItemsEnabled()
    {
        返回true;
    }

    @覆盖
    公共布尔的IsEnabled(INT位置)
    {
        返回true;
    }

    @覆盖
    公众诠释getCount将()
    {
        回报(0);
    }

    @覆盖
    公共对象的getItem(INT位置)
    {
        返回null;
    }

    @覆盖
    众长getItemId(INT位置)
    {
        返回(位置);
    }

    @覆盖
    公众诠释getItemViewType(INT位置)
    {
        返回0;
    }

    @覆盖
    公共查看getView(INT位置,查看convertView,父母的ViewGroup)
    {
        TextView的电视=新的TextView(m_context);

        tv.setText(项目);

        返回(电视);
    }

    @覆盖
    公众诠释getViewTypeCount()
    {
        返回1;
    }

    @覆盖
    公共布尔hasStableIds()
    {
        返回false;
    }

    @覆盖
    公共布尔的isEmpty()
    {
        返回false;
    }

    @覆盖
    公共无效registerDataSetObserver(DataSetObserver观察者)
    {
        m_observer =观测;
    }

    @覆盖
    公共无效unregisterDataSetObserver(DataSetObserver观察者)
    {
        m_observer = NULL;
    }
}
 

解决方案

GListView 对象被垃圾收集。至少 - 他们被称为与完成()时,手动GC从DDMS完成。不幸的是,DDMS HPROF文件似乎与我的版本与jHat 不兼容的,而我不是一个Eclipse用户,所以我没有准备好进入MAT。

I am struggling with a memory leak associated with a ListView. I have created the following small program which exhibits this behavior.

What I do is create 2 LinearLayouts. The first has a Button and a GListView control. The code for GListView is below, but it just sub-classes ListView, and implements the ListAdapter interface. When the GListView is created, it sets it's adapter to itself.

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

Run the program, and switch between the two views 20 times. Then bring up the DDMS and force a garbage collection. Then Dump the memory, and use the Memory Analyzer and you will find 21 GListView objects remaining. That is, the 20 GListViews that are not longer connected to anything have NOT been freed.

If I do a memory dump and take a look at one of the GListViews that should have been recycled, and list the incomming references 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 out the 'setAdapter(this)' function in the GListView constructor and repeat the above, I find that there is only 1 GListView that remains. That is, in this case, all of the unused GListViews have been properly recycled.

Someone suggested that I create a private class within my GListView to handle the ListAdapter interface, and I tried that, but it did not help. I have also tried creating a completely separate public class to handle the ListAdapter, but, alas, that doesn't seem to work either.

Surely there is some way to make these objects go away when they are no longer used anywhere. (Isn't that what garbage collection is all about?)

Any help would be appreciated. I am really pulling my hair out on this one.

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;
    }
}

解决方案

Your GListView objects are being garbage collected. Leastways, they are called with finalize() when a manual GC is done from DDMS. Unfortunately, the DDMS HPROF file seems incompatible with my version of jhat, and I'm not an Eclipse user so I do not have ready access to MAT.

这篇关于当Android中使用的ListView内存铅的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆