Animesh Jena
Animesh Jena

Reputation: 1551

RecyclerView index not updating while removing item using FirebaseRecycleradapter

I have implemented FirebaseRecyclerAdapter for a dynamic recyclerView and while I am trying to delete an item from the list, initially items at wrong indexes are getting deleted and after more items deletion, i am getting IndexOutOfBoundsException. I have already tried all solutions I found which can be seen as commented inside populateViewHolder() method. Please, if you have to downvote, at least give a proper answer and downvote it as I have already tried all solutions possible. Below I am posting my code. Please have a look.

Check the delete.setOnClickListener():

     adapter = new FirebaseRecyclerAdapter<Slc, viewHolder>(
                Slc.class,
                R.layout.single_slc_row,
                viewHolder.class,
                FirebaseDatabase.getInstance().getReference().child("DCU")) {
            @Override
            protected void populateViewHolder(final viewHolder viewHolder, final Slc model, final int position)
            {

                //expand collapse
                viewHolder.vis.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v)
                    {
                        // ViewAnimationsUtils.expand(viewHolder.inv);
                        viewHolder.collapse.setVisibility(View.VISIBLE);
                        viewHolder.inv.setVisibility(View.VISIBLE);

                    }
                });
                viewHolder.collapse.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v)
                    {
                        // ViewAnimationsUtils.collapse(inv);
                        viewHolder.inv.setVisibility(View.GONE);
                        viewHolder.collapse.setVisibility(View.GONE);
                    }
                });
                String s=adapter.getRef(position).getKey();
                viewHolder.name.setText(s);

                //dimming get
                viewHolder.dimming.setProgress(model.getPercentage());

                //on off get
                if(model.getON_OFF()==1)
                {
                    viewHolder.onOff.setChecked(true);
                }
                else if(model.getON_OFF()==0)
                {
                    viewHolder.onOff.setChecked(false);
                }

                //dimming set

                //viewHolder.dimming.incrementProgressBy(10);
                viewHolder.showProgress.setText( viewHolder.dimming.getProgress()+"%");
                viewHolder.dimming.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                    @Override
                    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
                    {
                        if(position!=RecyclerView.NO_POSITION)
                        {
                            if(seekBar.isShown() && fromUser)
                            {
                                progress= (progress/10)*10;
                                adapter.getRef(position).child("Percentage").setValue(progress);

                                viewHolder.showProgress.setText(progress+"%");
                            }
                        }


                    }

                    @Override
                    public void onStartTrackingTouch(SeekBar seekBar) {

                    }

                    @Override
                    public void onStopTrackingTouch(SeekBar seekBar) {

                    }
                });

                viewHolder.onOff.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

                    @Override
                    public void onCheckedChanged(CompoundButton buttonView,
                                                 boolean isChecked) {

                        if(buttonView.isPressed() &&isChecked){
                            adapter.getRef(position).child("ON_OFF").setValue(1);


                        }else{
                            adapter.getRef(position).child("ON_OFF").setValue(0);

                        }

                    }
                });
                viewHolder.delete.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v)
                    {
                        final Dialog dialog = new Dialog(myContext);
                        dialog.setTitle("Delete Slc?");
                        dialog.setContentView(R.layout.delete_slc);
                        dialog.setCancelable(false);
                        Window window = dialog.getWindow();
                        if(window == null) return;
                        WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
                        lp.copyFrom(dialog.getWindow().getAttributes());
                        lp.width = WindowManager.LayoutParams.MATCH_PARENT;
                        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
                        lp.gravity = Gravity.CENTER;
                        dialog.getWindow().setAttributes(lp);
                        TextView delete = (TextView)dialog.findViewById(R.id.deleteSlc);
                        final String key= adapter.getRef(position).getKey();
                        delete.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v)
                            {
                               // int pos = viewHolder.getAdapterPosition();

                                ref.child(key).setValue(null);



//                                int selectedItems = position;
//                                for (int i = selectedItems; i >= selectedItems; i--) {
//                                    adapter.getRef(i).removeValue();
                                   adapter.notifyItemRemoved(position);
//                                }
//                                adapter.getRef(position).removeValue();
//
//                                adapter.notifyItemRemoved(position);

                               // adapter.notifyDataSetChanged();

                                dialog.dismiss();
                            }
                        });


                        TextView dialogButton = (TextView) dialog.findViewById(R.id.canceld);
                        // if button is clicked, close the custom dialog
                        dialogButton.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v)
                            {
                                dialog.dismiss();
                            }
                        });

                        dialog.show();

                    }
                });
            }
        };

        slcList.setAdapter(adapter);

The exception I am getting after deleting some items:

  java.lang.IndexOutOfBoundsException: Invalid index 2, size is 2
                                                                              at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
                                                                              at java.util.ArrayList.get(ArrayList.java:308)
                                                                              at com.firebase.ui.database.FirebaseArray.getItem(FirebaseArray.java:52)
                                                                              at com.firebase.ui.database.FirebaseRecyclerAdapter.getRef(FirebaseRecyclerAdapter.java:150)

Upvotes: 3

Views: 1036

Answers (1)

koceeng
koceeng

Reputation: 2163

The error is caused by usage of position object inside of function not directly under populateViewHolder. Like in this one: (but not limited to)

protected void populateViewHolder(final viewHolder viewHolder, final Slc model, final int position) {
    // here position object is valid
    ...
    viewHolder.dimming.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged( ... ) {
            // but here, position object is likely to be incorrect
            // especially when you add/remove item of list
        }
        ...
    }

And the solution is simply to replace all the position objects that are not directly under populateViewHolder into viewHolder.getAdapterPosition().

Note: I copy it from my comment in case others seek for answer and miss the comment

Upvotes: 7

Related Questions