I have a RecyclerView
showing a list of items. The ViewHolder
for each rows contains a delete button, to remove the row. If I remove the last row and tap very fast on the disappearing row, I can crash my app because the second tap event is delivered to the removed row. I'm surprised that android delivers the second event. Before I try adding something like boolean isDeleted
to my ViewHolder
subclass, I'm wondering: am I doing something else wrong to get in this situation?
class MyAdapter extends RecyclerView.Adapter<MyViewHolder>
implements ItemTouchHelperAdapter {
List<Segment> segments;
MyAdapter(List<Segment> objs) {
this.segments = objs;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LinearLayout v = (LinearLayout) LayoutInflater.from(parent.getContext())
.inflate(R.layout.segment_edit_row, parent, false);
MyViewHolder vh = new MyViewHolder(v);
return vh;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Segment seg = segments.get(position);
holder.textView.setText(seg.getTitle());
holder.dragHandle.setOnTouchListener((v, event) -> {
if (MotionEventCompat.getActionMasked(event) ==
MotionEvent.ACTION_DOWN) {
onStartDrag(holder);
}
return false;
});
holder.deleteButton.setOnClickListener(v -> {
segments.remove(position);
notifyItemRemoved(position);
});
View.OnClickListener editExerciseListener = v -> {
Segment segment = segments.get(position);
startEditSegmentActivity(segment, position);
};
holder.textView.setOnClickListener(editExerciseListener);
holder.arrow.setOnClickListener(editExerciseListener);
}
The deleteButton
handler runs first, and then the editExerciseListener
, with the position
that is now out of bounds.
Update
Several people have suggested I call notifyDataSetChanged
. The Android docs specifically recommend not to do that if you can describe your change with a call to notifyItemRemoved
instead.
Are those docs wrong?