设置标记时,Android GRef会增加

时间:2012-07-26 13:57:08

标签: android memory reference

我正在处理日历活动,并已实现了一个用于处理数据的适配器。对于一个月中的每一天,我都有一个按钮,我为其设置了标签。然后当按下按钮时,我可以告诉它来自标签的日期。可以跳到下一个/上个月,从而更改日历视图的数据。但是我的问题是,每次我设置按钮的标签(因为视图被重用),GRef会增加并且永远不会释放,当它达到2000时应用程序会崩溃。取消注释设置标记的代码行时,Gref不会增加,应用程序也不会崩溃。 以下方法来自我的适配器:

 private int key = Resource.Id.string_key;     
public override View GetView(int position, View convertView, ViewGroup parent)
            {
                View row = convertView;
                if (row == null)
                {
                    LayoutInflater inflater = (LayoutInflater)_context.GetSystemService(Context.LayoutInflaterService);
                    row = inflater.Inflate(Resource.Layout.calendar_grid_cell, parent, false);
                }

                // Get a reference to the Day gridcell
                gridcell = (Button)row.FindViewById(Resource.Id.calendar_day_gridcell);
                gridcell.SetOnClickListener(this);
                string[] words = list[position].Split(delimiterChars);
                gridcell.Text = words[2];
                gridcell.SetTag(key, words[1]);

                return row;
            }

有人建议我能做些什么吗?我在设置新标记之前尝试将tag属性设置为null - 或者我应该避免使用标记并找到其他方法吗?

1 个答案:

答案 0 :(得分:2)

这里的问题有两个:

  1. 您正在致电View.SetTag(int, Java.Lang.Object)

  2. string to Java.Lang.Object隐式转换。

  3. 所以这个:

    gridcell.SetTag(key, words[1])
    

    在道德上相当于:

    Java.Lang.Object tmp = words[1];
    gridcell.SetTag(key, tmp);
    

    这导致gref被消耗,并且可能永远不会被收集,因为Android持有Dalvik端java.lang.String实例,这意味着Android的GC的Mono将相信{{1无法收集实例。

    幸运的是,我们知道的更好,并且可以相应地行事。将您的代码更改为:

    tmp

    这将是包装器实例的using (var tag = new Java.Lang.String(words[1])) gridcell.SetTag(key, tag); ,这很好(在这种情况下是),因为我们不需要它,我们知道我们不需要它。

    注意very careful时,您必须making use of things you "know"

    这就是事情的初始方面。事物的查找方面是相同但不同的:

    Dispose()

    这是有效的,因为View.findViewWithTag()被记录为使用using (var tag = new Java.Lang.String("some-tag")) { var gridcell = row.FindViewWithTag(tag).JavaCast<Button>(); // use gridcell... } 而不是引用相等,因为我们在这里使用字符串,所以我们使用Object.equals(),它执行值相等。

    如果grefs是一个主要问题,你可以更进一步处理String.equals() gref,,除非 gridcell可以是C#子类。 (了解这需要访问您的gridcell。)

    .axml