mindoverflow
mindoverflow

Reputation: 926

RecyclerView items not repeating, but retaining changes of previous item that was in its slot

I am trying to implement a list of files that can be selected from the RecyclerView Adapter class. While I understand it is not a good idea, I feel if I am able to accomplish this from within said class, it would be really helpful in the future. My list item (Each individual item view for the RecyclerView) has the following structure:

|--------|----------------|
|  ICON  |      DATA      |
|--------|----------------|
public class RVA extends RecyclerView.Adapter<RVA.RVH>
{
    private LayoutInflater inf;
    private ArrayList<File> items;

    // The var below is used to track the no. of selected items
    // globally within the RVA class.
    private int numberOfSelectedItems = 0; 

    public RVA(ArrayList<File> _items)
    {
        items = _items;
    }

    @Override
    public RVA.RVH onCreateViewHolder(ViewGroup parent, int viewType)
    {
        inf = LayoutInflater.from(parent.getContext());
        return new RVH(inf, parent);
    }

    @Override
    public void onBindViewHolder(RVA.RVH holder, int position)
    {
        File listItem = items.get(position);

        // 'binding' each file element to a respective host container.
        holder.bind(listItem);
    }

    @Override
    public int getItemCount()
    {
        return items.size();
    }

    @Override
    public long getItemId(int position)
    {
        return position;
    }

    // The ViewHolder class.
    // Initially it was just declared as class.
    // There was no change observed after the 'final' modifier was added.
    final class RVH extends RecyclerView.ViewHolder
    {
        private Context context;
        private LinearLayout itemSelector;
        private ImageView itemIcon;
        private TextView itemName;
        private TextView itemSize;

        public RVH(LayoutInflater inf, ViewGroup parent)
        {
            super(inf.inflate(R.layout.list_item, parent, false));
            context = parent.getContext();

            // This is the SECOND outermost LinearLayout of each file item View.
            // It was previously the parent Layout, but there was no difference due to change.
            itemSelector = itemView.findViewById(R.id.item_selector);

            // This is the icon ImageView.
            itemIcon = itemView.findViewById(R.id.item_icon);

            // These are the data TextViews.
            itemName = itemView.findViewById(R.id.item_id);
            itemSize = itemView.findViewById(R.id.item_size);
        }

        // The 'bind' method that registers changes.
        public void bind(File fileItem)
        {
            String listItemName = fileItem.getName();
            itemName.setText(listItemName);

            //---- These are just changes to the icons depending on type. Works fine.
            if(fileItem.isDirectory())
            {
                itemIcon.setImageResource(R.drawable.directory_icon);
                itemSize.setText("Directory");
            }
            else
            {
                itemSize.setText(fileItem.length() + " B");
                if(listItemName.endsWith(".jpg") || listItemName.endsWith(".jpeg") || listItemName.endsWith(".png") || listItemName.endsWith(".gif"))
                {
                    Glide.with(context).load(fileItem).centerCrop().into(itemIcon);
                }
                else
                {
                    itemIcon.setImageResource(R.drawable.file_icon);
                }
            }
            //---- END

            //---- This is the code which handles opening files according to type. Works fine.
            itemSelector.setOnClickListener(new View.OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    if(numberOfSelectedItems == 0)
                    {
                        if(!itemSize.getText().toString().endsWith(" B"))
                        {
                            Intent loadListItemIntent = new Intent(context, DirectoryViewActivity.class);
                            loadListItemIntent.putExtra("ITEMPATH", fileItem.getPath());
                            context.startActivity(loadListItemIntent);
                        }
                        else
                        {
                            if(itemName.getText().toString().endsWith(".jpg") || itemName.getText().toString().endsWith(".jpeg") || itemName.getText().toString().endsWith(".png") || itemName.getText().toString().endsWith(".gif"))
                            {
                                Glide.with(context).load(fileItem).centerCrop().into(itemIcon);
                                Intent loadListItemIntent = new Intent(context, ImageActivity.class);
                                loadListItemIntent.putExtra("ITEMPATH", fileItem.getPath());
                                context.startActivity(loadListItemIntent);
                            }
                            else
                            {
                                Toast.makeText(context, "File needs proper application.", Toast.LENGTH_SHORT).show();
                            }
                        }
                    }
                }
            });
            //---- END

//---- !!! THIS SECTION is where the problem manifests.
            itemIcon.setOnClickListener(new View.OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    if(itemIcon.getTag().toString().equals("not_selected"))
                    {
                        // Incrementing based on selection.
                        ++numberOfSelectedItems;

                        // Using a tag to identify/ denote whether item is selected.
                        itemIcon.setTag("selected");

                        // Changing the background & disabling file opening while in selection mode.
                        itemSelector.setBackgroundResource(R.drawable.list_item_selected);
                        itemSelector.setClickable(false);
                        itemSelector.setLongClickable(false);

                        // I use this odd method to send a message to the host Activity
                        // that we have entered selection mode & that the Activity should
                        // display some option buttons on the Action Bar.
                        if(context instanceof DirectoryViewActivity)
                        {
                            ((DirectoryViewActivity)context).addSelectedItem(fileItem);
                            if(numberOfSelectedItems == 1)
                            {
                                ((DirectoryViewActivity)context).setSelectionMode();
                            }
                        }
                    }
                    else
                    {
                        // Decrementing based on deselection.
                        --numberOfSelectedItems;

                        // Overwiting the tag to identify/ denote item is now unselected.
                        itemIcon.setTag("not_selected");

                        // Background changed back to default & file opening re-enabled.
                        itemSelector.setClickable(true);
                        itemSelector.setLongClickable(true);
                        itemSelector.setBackgroundResource(R.drawable.list_item_background);

                        // I use this method to send a message to the host Activity
                        // that we have exited selection mode & that the Activity should
                        // remove related option buttons from the Action Bar.
                        if(context instanceof DirectoryViewActivity)
                        {
                            ((DirectoryViewActivity)context).removeSelectedItem(fileItem);
                            if(numberOfSelectedItems == 0)
                            {
                                ((DirectoryViewActivity)context).voidSelectionMode();
                            }
                        }
                    }
                }
            });
        }
    }
}

Upvotes: 0

Views: 561

Answers (1)

Abhinav Chauhan
Abhinav Chauhan

Reputation: 1384

This is because RecyclerView does not create views for all of your items in the list it create enough ViewHolder to fill up the screen and few more and when you scroll the old ViewHolder are bind to some other data in the adapter that is when the onBindViewHolder() is called , so basically what is happening here is you are setting the background of current ViewHolder on the screen and when you scroll the same ViewHolder in bind to the new data.

I think you have to check in the onBindViewHolder whether or not this is the item to which you want to set the background and then take the decision remove it if the item is not selected in the dataset set background if it is selected.

Upvotes: 2

Related Questions