Prevent reuse of first item view in RecycleView grid with the user of SetTag/GetTag on scroll

I am creating an app and within this app I have created a grid of images with recycleview. The first item displays the current user's photo while the other images displays images of other users. In order to set the correct image for the first item I use a variable count. If count == 0 then set correct image. Unfortunately, the first item image that is loaded is changed when the grid is scrolled to a default background resource image. Of course this is due to the reuse of views by the ItemViewHolder. So my question is how do I maintain the correct image in the first item when the grid is scrolled. From my research so far what might work is SetTag/GetTag. However, I am not sure to use it in this case. Any help would be appreciated.

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

            ItemViewHolder ivh = new ItemViewHolder(itemview, OnClick);
            ISharedPreferences iSharedPref = PreferenceManager.GetDefaultSharedPreferences(itemview.Context);
            ISharedPreferencesEditor iSharedPrefEditor = iSharedPref.Edit();
            var genImage = itemview.FindViewById<SquareImageView>(Resource.Id.grid_item_image);
            var count = ii++;              

            if (count == 0)
            {

                string image = string.Empty;
                if (iSharedPref.GetString("Gender", "Male").ToString() == "Female")
                {
                    genImage.SetBackgroundResource(Resource.Mipmap.Female);                       

                }
                else
                {
                    genImage.SetBackgroundResource(Resource.Mipmap.Male);

                    ivh._ProfileImage.SetTag(Resource.Mipmap.Male, count);
                }
            }
            else
            {
                if (iSharedPref.GetString("Seeking", "Female").ToString() == "Female")
                {
                    genImage.SetBackgroundResource(Resource.Mipmap.Female);                         
                }
                else
                {
                    genImage.SetBackgroundResource(Resource.Mipmap.Male);

                }
            }

            return ivh;
        }
        catch (Exception ex)
        {
            FirebaseCrash.Report(ex);

            return null;
        }
    }

1 answer

  • answered 2018-11-06 07:14 SushiHangover

    You should reduce your OnCreateViewHolder to just instancing, setting up that view and returning the ViewHolder, and then handle the binding in the OnBindViewHolder override, that way you have a stable ID to act upon.

    Something like:

    public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
    {
        var itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.app_info, parent, false);
        return new ItemViewHolder(itemview); // "OnClick" should be added in the OnBindViewHolder and removed in the OnViewRecycled
    }
    

    Now in the OnBindViewHolder, you are passed a stable position value that you can act upon (in your case, a position of zero would be a special case). In this override, you would handle assigning values to your ViewHolder, add listeners/event handlers, etc..:

    public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
    {
        var viewHolder = holder as ItemViewHolder;
        if (position == 0)
        {
           ~~~
        }
        else
        {
           ~~~
        }
    }
    

    In the OnViewRecycled override, remove any listeners/event handlers, etc.. to prevent memory leaks, etc...

    public override void OnViewRecycled(Java.Lang.Object holder)
    {
        var viewHolder = holder as ItemViewHolder;
        ~~~
    
        base.OnViewRecycled(holder);
    }