【问题标题】:Android GRef increase when setting tag of view设置视图标签时Android GRef增加
【发布时间】:2012-07-26 13:57:08
【问题描述】:

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

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

【问题讨论】:

    标签: android memory reference


    【解决方案1】:

    这里的问题是双重的:

    1. 你打电话给View.SetTag(int, Java.Lang.Object)

    2. 存在从string to 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(),这很好(在这种情况下!)因为我们不需要它,而且我们知道我们不需要它'不需要它。

    注意making use of things you "know"时你必须是very careful

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

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

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

    如果 grefs 是一个主要问题,您可以更进一步并处理 gridcell gref,除非 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;
    }
    

    【讨论】:

      猜你喜欢
      • 2017-12-14
      • 1970-01-01
      • 1970-01-01
      • 2018-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-10
      相关资源
      最近更新 更多