1

我正在处理日历活动并实现了一个适配器来处理数据。对于一个月中的每一天,我都有一个按钮,我为其设置了一个标签。然后,当按下按钮时,我可以从标签中分辨出它是哪个日期。可以跳到下个月/上个月,从而更改日历视图的数据。但是我的问题是,每次我设置按钮的标签(因为视图被重用)时,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;
            }

有人对我能做什么有建议吗?在设置新标签之前,我已经尝试将标签属性设置为空 - 或者我应该避免使用标签并找到其他方式吗?

4

1 回答 1

2

这里的问题是双重的:

  1. 您正在调用View.SetTag(int, Java.Lang.Object)

  2. 存在从字符串到 Java.Lang.Object的隐式转换。

所以这:

gridcell.SetTag(key, words[1])

在道德上相当于:

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

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

幸运的是,我们知道得更多,并且可以做出相应的行为。将您的代码更改为:

using (var tag = new Java.Lang.String(words[1]))
    gridcell.SetTag(key, tag);

Dispose()是包装器实例的意志,这很好(在这种情况下!)因为我们不需要它,而且我们知道我们不需要它。

注意:使用“知道”的东西时必须非常小心

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

using (var tag = new Java.Lang.String("some-tag")) {
    var gridcell = row.FindViewWithTag(tag).JavaCast<Button>();
    // use gridcell...
}

这是有效的,因为View.findViewWithTag()被记录为使用Object.equals()而不是引用相等,并且由于我们在这里使用字符串,所以我们正在使用String.equals(),它执行值相等。

如果 gref 是一个主要问题,您可以更进一步并处理gridcellgref,除非 gridcell它可能是 C# 子类。(知道这一点需要访问您的.axml.)

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
    using (var gridcell = row.FindViewById<Button>(Resource.Id.calendar_day_gridcell)) {
        gridcell.SetOnClickListener(this);
        string[] words = list[position].Split(delimiterChars);
        gridcell.Text = words[2];
        using (var tag = new Java.Lang.String(words[1]))
            gridcell.SetTag(key, tag);
    }

    return row;
}
于 2012-12-18T19:36:36.720 回答