RecyclerView.OnBindViewHolder点击多次被调用?

时间:2015-09-12 14:59:09

标签: android xamarin.android android-recyclerview

我有一个Grid RecyclerView(3列),我在OnBindViewHolder方法中添加了一个委托点击监听器。

场景(附加日志)

假设我有18个项目,即6行。默认情况下没有任何滚动,我只能看到2.5行。

当我点击项目(位置0-8)时,委托函数只被调用一次(尝试1~2)。

当我滚动到页面末尾,然后单击其中一个项目时,委托函数将被调用一次(尝试3)。

如果我向上滚动,然后单击其中一个项目,委托函数将被调用4次(尝试4)。

在我的(尝试5)中,我将其滚动到底部并单击一个项目,这次,委托函数被调用两次。

注意:

  • 我正在使用Xamarin.Android
  • 我只点击了那些项目
  • 我已经使用多个设备进行了测试并获得了相同的结果
  • 调用的委托函数数量不固定,有时每次点击最多可调用6次。
  

我的问题是为什么会发生这种情况,还有其他正确的方法来实现吗?

日志

// Attempt 1 : (I clicked position 1)
[[Log ==== ]] [Time : 9/12/2015 10:36:44 AM ] Clicked position [1]
// Attempt 2 : (I clicked position 3)
[[Log ==== ]] [Time : 9/12/2015 10:36:52 AM ] Clicked position [3]
// Attempt 3 : (I scroll it till the end of the page and clicked position 14)
[[Log ==== ]] [Time : 9/12/2015 10:36:52 AM ] Clicked position [14]
// Attempt 4 : (I scroll it back to the top and clicked position 1)
[[Log ==== ]] [Time : 9/12/2015 10:40:08 AM ] Clicked position [4]
[[Log ==== ]] [Time : 9/12/2015 10:40:08 AM ] Clicked position [15]
[[Log ==== ]] [Time : 9/12/2015 10:40:08 AM ] Clicked position [5]
[[Log ==== ]] [Time : 9/12/2015 10:40:08 AM ] Clicked position [16]
[[Log ==== ]] [Time : 9/12/2015 10:40:08 AM ] Clicked position [1]
// Attempt 5 : (I scroll it down again and clicked position 14)
[[Log ==== ]] [Time : 9/12/2015 10:41:57 AM ] Clicked position [11]
[[Log ==== ]] [Time : 9/12/2015 10:41:57 AM ] Clicked position [14]

活动

[Activity (Label = "DrinksMenuCategory", Theme = "@style/AppTheme.ActionBar")]          
public class DrinksMenuCategory : AppCompatActivity
{
    private RecyclerView mRecyclerView;
    private RecyclerView.LayoutManager mLayoutManager;
    private RecyclerView.Adapter mAdapter;

    private int selected_drinksCategory;
    private List<Drinks> drinksCategory;

    protected override void OnCreate (Bundle bundle)
    {
        base.OnCreate (bundle);
        SetContentView (Resource.Layout.Activity_DrinksMenuCategoryGridview);
        SupportActionBar.SetDisplayHomeAsUpEnabled (true);

        mRecyclerView = FindViewById<RecyclerView> (Resource.Id.recyclerView_drinksMenuCategoryGridView);
        mRecyclerView.HasFixedSize = true;

        mLayoutManager = new GridLayoutManager (this, 3);
        mRecyclerView.SetLayoutManager (mLayoutManager);
        mAdapter = new DrinksMenuCategoryRecyclerAdapter (drinksCategory, mRecyclerView);
        mRecyclerView.SetAdapter (mAdapter);
    }
}

适配器&amp; ViewHolder

public class DrinksMenuCategoryRecyclerAdapter : RecyclerView.Adapter
{
    public List<Drinks> mDrinksItems;
    public RecyclerView mRecyclerView;

    public DrinksMenuCategoryRecyclerAdapter (List<Drinks> drinksItems, RecyclerView mRecyclerView)
    {
        this.mDrinksItems = drinksItems;
        this.mRecyclerView = mRecyclerView;
    }

    public override int GetItemViewType (int position)
    {
        return Resource.Layout.recyclerView_cell_drinksMenu_category;
    }

    public override RecyclerView.ViewHolder OnCreateViewHolder (ViewGroup parent, int viewType)
    {
        View row = LayoutInflater
            .From (parent.Context)
            .Inflate (Resource.Layout.recyclerView_cell_drinksMenu_category, parent, false);

        CardView v_drinksCard = row.FindViewById<CardView> (Resource.Id.drinks_card);
        ImageView v_drinksImage = row.FindViewById<ImageView> (Resource.Id.drinks_image);
        TextView v_drinksText = row.FindViewById<TextView> (Resource.Id.drinks_text);

        DrinksMenuItemHolder viewHolder = new DrinksMenuItemHolder (row, parent.Context) {
            mDrinksCard = v_drinksCard,
            mDrinksImage = v_drinksImage,
            mDrinksText = v_drinksText
        };

        return viewHolder;
    }

    public override void OnBindViewHolder (RecyclerView.ViewHolder holder, int position)
    {
        DrinksMenuItemHolder viewHolder = holder as DrinksMenuItemHolder;
        viewHolder.mDrinksCard.Click += delegate {
            // *** Click Event ***
            Log.Debug ("[DrinksMenuCategoryRecyclerAdapter ==== ]", "[Time : " + DateTime.Now + " ] Clicked position [" + position + "]");
            Toast.MakeText (viewHolder.context, "[Time : " + DateTime.Now + " ] Clicked position [" + position + "]", ToastLength.Short).Show (); 
        };
        viewHolder.mDrinksText.Text = mDrinksItems[position].name;
    }

    public override int ItemCount {
        get { return mDrinksItems.Count; }
    }

    public class DrinksMenuItemHolder : RecyclerView.ViewHolder
    {
        public Context context { get; set; }
        public View mMainView { get; set; }

        public CardView mDrinksCard { get; set; }
        public ImageView mDrinksImage { get; set; }
        public TextView mDrinksText { get; set; }

        public DrinksMenuItemHolder (View view, Context context) : base (view)
        {
            this.context = context;
            mMainView = view;
        }
    }
}

1 个答案:

答案 0 :(得分:0)

(我知道我迟到了,但无论如何......)

viewHolder.mDrinksCard.Click += delegate {..}

每次绑定ViewhHolder(发生很多事情)时,您都会创建一个新委托并将其添加到潜在的现有视图中。随着时间的推移,视图会累积多个Click个代表,每个代表依次响应一次点击。

您需要断开连接,删除Click中的Adapter.onViewRecycled()代理。