为何RecyclerView条目位置返回值为-1?
Hey there! Let's tackle that frustrating problem where you get a -1 position when trying to delete RecyclerView items via long press. This is a common pitfall with RecyclerView's view recycling mechanism, so here are the most reliable fixes and explanations:
1. Use getBindingAdapterPosition() instead of getAdapterPosition()
The old getAdapterPosition() method can return -1 (aka RecyclerView.NO_POSITION) if the ViewHolder has been recycled or the adapter's data has changed since the ViewHolder was bound. Starting with AndroidX RecyclerView 1.2.0, getBindingAdapterPosition() is the safer choice—it accounts for the current bound adapter (critical if you're using something like ConcatAdapter) and gives a more accurate position.
Always add a check to ensure the position is valid before proceeding with deletion:
holder.itemView.setOnLongClickListener(v -> { int currentPosition = holder.getBindingAdapterPosition(); if (currentPosition != RecyclerView.NO_POSITION) { // Safe to perform delete operation here removeItem(currentPosition); return true; } return false; });
2. Reset click listeners in onBindViewHolder()
RecyclerView reuses ViewHolders, so if you set a click listener once (like in onCreateViewHolder()), the listener might still reference an old position when the ViewHolder is reused. Always reattach the long click listener inside onBindViewHolder() to ensure it's tied to the current item's position:
@Override public void onBindViewHolder(ItemViewHolder holder, int position) { // Bind your data to the ViewHolder first holder.bind(mDataList.get(position)); // Reset the long click listener for the current item holder.itemView.setOnLongClickListener(v -> { int validPosition = holder.getBindingAdapterPosition(); if (validPosition != RecyclerView.NO_POSITION) { removeItem(validPosition); return true; } return false; }); }
3. Update your data set correctly
When deleting an item, make sure you modify your data collection first, then notify the adapter with the specific position change—not just notifyDataSetChanged(). Using notifyItemRemoved() helps RecyclerView maintain correct position tracking for remaining items:
private void removeItem(int position) { // Remove the item from your data source first mDataList.remove(position); // Notify the adapter of the exact item removal notifyItemRemoved(position); // Optional: Notify subsequent items their positions have shifted (for smooth animations) notifyItemRangeChanged(position, mDataList.size() - position); }
Avoid notifyDataSetChanged() here—it forces a full refresh, which can break position tracking and kill animations.
4. Enable stable IDs
Setting stable IDs helps RecyclerView track items more reliably, even when data changes. Enable this in your adapter constructor and override getItemId() to return a unique ID for each item:
public class MyItemAdapter extends RecyclerView.Adapter<ItemViewHolder> { public MyItemAdapter() { setHasStableIds(true); } @Override public long getItemId(int position) { // Return a unique ID for your item (e.g., from your data model's ID field) return mDataList.get(position).getUniqueId(); } }
5. Avoid holding references to ViewHolders outside onBindViewHolder()
If you store ViewHolder references elsewhere (like in a list), those references might point to recycled ViewHolders that no longer have a valid position. Stick to handling interactions directly within onBindViewHolder() or ensure any stored references are actively bound to the RecyclerView.
Quick Recap
The biggest fixes are:
- Replace
getAdapterPosition()withgetBindingAdapterPosition() - Always check if the position is not
RecyclerView.NO_POSITIONbefore acting - Reset click listeners in
onBindViewHolder() - Use precise adapter notifications (
notifyItemRemoved()instead ofnotifyDataSetChanged())
These steps should eliminate those random -1 position issues and make your long-press deletion work reliably.
内容的提问来源于stack exchange,提问作者Srinivas Nahak

