'Recyclerview notifyItemRemoved removes a wrong item and not working properly when using view binding

When removing an item from recycler view, it is not working properly. For instance, if you remove beginning from the start it removes other items that are not pressed or it won't remove some of them even if you pressed it

Activity Class

List<ModelPlayers> modelPlayers = new ArrayList<>();

modelPlayers.add(new ModelPlayer(R.drawable.photo_ronaldo,"Ronaldo"));
modelPlayers.add(new ModelPlayer(R.drawable.photo_messi,"Messi"));
modelPlayers.add(new ModelPlayer(R.drawable.photo_neymar,"Neymar"));
modelPlayers.add(new ModelPlayer(R.drawable.photo_mbappe,"Mbappe"));
modelPlayers.add(new ModelPlayer(R.drawable.photo_ramos,"Ramos"));

LinearLayoutManager llm= new LinearLayoutManager(activity);
mRecyclerView.setLayoutManager(llm);
mRecyclerView.setHasFixedSize(true);

AdapterPlay adapterPlay= new AdapterPlay(activity, modelPlayers);
mRecyclerView.setAdapter(adapterPlay);

Adapter Class

public class AdapterPlay extends RecyclerView.Adapter<AdapterPlay.PlayerViewHolder> {

    public static class PlayerViewHolder extends RecyclerView.ViewHolder {
        PlayerViewHolder(View itemView) {
            super(itemView);
        }
    }

    private Activity mActivity;
    private List<ModelPlayers> modelPlayers = new ArrayList<>();
    private ItemPlayBinding mBinding;

    public AdapterPlay(Activity activity, List<ModelPlayers> modelPlayers) {
        this.mActivity=activity;
        this.modelPlayers = modelPlayers;
    }


    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
    }

    @Override
    public PlayerViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        mBinding= ItemPlayBinding.inflate(LayoutInflater.from(mActivity),viewGroup,false);
        return new PlayerViewHolder(mBinding.getRoot());
    }


    @Override
    public void onBindViewHolder(PlayerViewHolder PlayerViewHolder, int i) {
        ModelPlayers modelPlayer = this.modelPlayers.get(i);
        mBinding.mainImage.setImageResource(modelPlayer.getImage());
        mBinding.mainText.setText(modelPlayer.getTitle());

        mBinding.mainText.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                modelPlayers.remove(i);
                notifyItemRemoved(i);
//                notifyItemRangeChanged(i,modelPlays.size());
            }
        });
    }

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


Solution 1:[1]

I finally found out the problem existed because of improper usage of view binding in adapter class.

The changes is only made from the adapter class.

public class AdapterPlay extends RecyclerView.Adapter<AdapterPlay.PlayerViewHolder> {

    public static class PlayerViewHolder extends RecyclerView.ViewHolder {
        //made changes here, placing the binding here in the viewholder
        private ItemPlayBinding mBinding;
        PlayerViewHolder(ItemPlayBinding binding){
            super(binding.getRoot());
            mBinding = binding;
        }
    }

    private Activity mActivity;
    private List<ModelPlayer> modelPlayers = new ArrayList<>();

    public AdapterPlay(Activity activity, List<ModelPlayer> modelPlayers) {
        this.mActivity=activity;
        this.modelPlayers = modelPlayers;
    }


    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
    }

    @Override
    public PlayerViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        //made changes here
        return new PlayerViewHolder(ItemPlayBinding.inflate(
                LayoutInflater.from(mActivity),viewGroup,false));
    }


    @Override
    public void onBindViewHolder(PlayerViewHolder playerViewHolder, int i) {
        ModelPlayer modelPlayer = this.modelPlayers.get(i);
        //instead of the first mbinding.view I know make it viewholder.mbinding.view
        playerViewHolder.mBinding.mainImage.setImageResource(modelPlayer.getImage());
        playerViewHolder.mBinding.mainText.setText(modelPlayer.getTitle());
        playerViewHolder.mBinding.mainText.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                modelPlayers.remove(i);
                notifyItemRemoved(i);
                notifyItemRangeChanged(i,getItemCount());
            }
        });
    }

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

Solution 2:[2]

Man, i had the same problem! Creating the binding inside the ViewHolder like this:

public class MyViewHolder extends RecyclerView.ViewHolder {
    ItemProductResumeBinding binding;
    public MyViewHolder(ItemProductResumeBinding binding) {
        super(binding.getRoot());
        this.binding = binding;
    }
}

and inflating it like this:

@NonNull
@Override
public ProductsAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    return new ProductsAdapter.MyViewHolder(ItemProductResumeBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
}

solved the problem. Thanks! Saved my day!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Aman
Solution 2 gnovakovski