Richard Richard - 3 months ago 35
Android Question

RecyclerView insert /remove animation deletes unwanted object

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);
}

Answer

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 position of element is not equal to -1 and position of element should be less than size of total elements in list. hence not causing unwanted crash due to indexes of elements.

Comments