1

私はカレンダー活動を扱っており、データを処理するためのアダプターを実装しています。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;
            }

私にできることについて誰か提案がありますか?新しいタグを設定する前に、タグ プロパティを null に設定しようとしました。または、タグの使用を避けて他の方法を見つける必要がありますか?

4

1 に答える 1

2

ここでの問題は 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);

Android が Dalvik 側のインスタンスを保持しているため、これにより gref が消費され、おそらく収集されることはありません。これ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()、値の等価性を実行する を使用しています。

グレフが大きな懸念事項である場合は、C# サブクラスでない限り、さらに一歩進んでgridcellグレフを破棄できます。(これを知るには、にアクセスする必要があります。) gridcell.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 に答える