3

Please friends help me I am Stuck in solving this RecyclerView Problem. I am new to RecyclerView and created a RecyclerView that simply have a todo-like application for managing tasks.

The problems are:

  • When i remove any item and call notifyItemRemoved() it sometime deletes undesired item and the app crashes. (may be because indexes mesh up)
  • Even when i update by again calling setAdapter, undesired things happen(see #here mark in code.). The color is set to desired items on start but after scrolling down it applies to all those are scrolled up.

Here is my adapter:

public class RVadapter extends RecyclerView.Adapter<RVadapter.mHolder> {

    public List<Task> mTask;
    private SQLhelper sql;
    private Context mContext;
    public RVadapter(Context context)
    {
        super();
        mContext=context;
        sql=new SQLhelper(mContext,null);
        PlannerAI ai=new PlannerAI();
        mTask=ai.generateTaskList(sql.getTasks());
    }

    public interface listener {
        public void refresh();
    }

    @Override
    public void onBindViewHolder(mHolder holder,final int i) {
        try {
            final Task t = mTask.get(i);
            // #here
            if(t.getId().equals("Enjoy"))
            {
               holder.vv.setBackgroundColor(mContext.getResources().getColor(android.R.color.some_color)); 
            }
            holder.name.setText(t.getName());
            holder.extras.setText(t.getExtras());
            holder.id.setText(t.getId());
            holder.subject.setText(t.getSubject());
            holder.type.setText(t.getType());
            holder.noq.setText(t.getNo()+" questions");
            holder.del.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(t.id!=null) {
                        sql.deleteTask(t.id);
                        mTask.remove(i);
                        notifyItemRemoved(i);
                        if (mContext instanceof listener) {
                            ((listener) mContext).refresh();
                        }
                    }
                }
            });
        }catch(Exception e){
            Log.d("TAG_LOG_EM",e.toString());
        }
    }


    @Override
    public mHolder onCreateViewHolder(ViewGroup parent, int viewType) {
       mHolder view;
        view = null;
        try{
            View v=LayoutInflater.from(parent.getContext()).inflate(R.layout.planner_item,null);
            view=new mHolder(v);

       }catch(Exception e){
           Log.d("TAG_LOG_EM",e.toString());
       }
        return view;
    }

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

    class mHolder extends RecyclerView.ViewHolder{
        public TextView name;
        public TextView extras;
        public TextView id;
        public TextView subject;
        public TextView type;
        public TextView noq;
        public View vv;
        public ImageView del;

        public mHolder(View view){
            super(view);
            vv=view;
            try {
                name = (TextView) view.findViewById(R.id.planner_name);
                extras = (TextView) view.findViewById(R.id.planner_extras);
                id = (TextView) view.findViewById(R.id.planner_id);
                del = (ImageView) view.findViewById(R.id.t_delete);
                subject = (TextView) view.findViewById(R.id.planner_subject);
                type = (TextView) view.findViewById(R.id.planner_type);
                noq = (TextView) view.findViewById(R.id.planner_no);
            }catch(Exception e){
                Log.d("TAG_LOG_EM",e.toString());
            }
        }

    }
}

I don't the SQL and MainActivity classes are needed(please comment if needed). Please Help and tell any recommended changes in code. Thanks!

Edit: The refresh function is:

public void refresh(){

        radapter = new RVadapter(this);
        rv.setAdapter(radapter);
    }
Vasily Kabunov
  • 6,511
  • 13
  • 49
  • 53
Mrigank
  • 136
  • 1
  • 8
  • Do you need to have the refresh function ? What happens if you remove it ? It creates a new adapter which seems like unnecessary work. Check this answer out here http://stackoverflow.com/questions/26076965/android-recyclerview-addition-removal-of-items and try calling also notifyItemRangeChanged function. – Jason Saruulo Oct 01 '15 at 15:02

1 Answers1

17

Just put these functions inside your RVadapter

public void onItemDismiss(int position) {
    if(position!=-1 && position<mTask.size())
    {
        mTask.remove(position);
        notifyItemRemoved(position);
        notifyItemRangeChanged(position, getItemCount());
    }
}

it provides the count of total elements currently present in the adapter

@Override
public int getItemCount() {
    return (null != mTask ? mTask.size() : 0);
}

and in your onClick(), just add :

holder.del.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
          onItemDismiss(i)
    }
});

Edit 1: Explanation

mTask.remove(position); - removes the element at particular position from the List.

notifyItemRemoved(position); - notifies the RecyclerView Adapter that data in adapter has been removed at a particular position.

notifyItemRangeChanged(position, getItemCount()); - notifies the RecyclerView Adapter that positions of element in adapter has been changed from position(removed element index to end of list), please update it.

if(position!=-1 && position<mTask.size()) - this condition verifies that the position of an element is not equal to -1 and the position of an element should be less than the size of total elements in the list. hence not causing an unwanted crash due to indexes of elements.

Vipul Asri
  • 8,903
  • 3
  • 46
  • 71