RecyclerView中CardView按钮事件错位:点击首项触发末项问题修复
问题解决:RecyclerView按钮点击触发错误Item数据操作
问题原因
- 全局变量被复用覆盖:Adapter中定义的
idVolunteer、idOrganization、documentPendingID是类成员变量,RecyclerView的ViewHolder会被复用,每次执行onBindViewHolder都会更新这些变量的值,导致点击按钮时,变量存储的是最后一次绑定的Item数据,而非当前点击的Item数据。 - 异步查询的时序问题:
onBindViewHolder中发起的Firestore查询是异步执行的,当查询完成时,当前ViewHolder可能已经被复用给其他Item,documentPendingID会被后续绑定的Item修改,最终删除的是最后一条查询到的文档。 - 查询条件不准确:使用
whereEqualTo("organizationId", idOrganization)会查询该组织下所有的待处理请求,而非当前Item对应的单条请求,循环赋值后documentPendingID只会保留最后一条查询结果的ID。
解决方案
- 移除全局变量,使用局部变量或当前Item的快照ID:利用
FirestoreRecyclerAdapter的getSnapshots().getSnapshot(position).getId()直接获取当前Item对应的Firestore文档ID,无需额外查询。 - 直接使用当前Item的Request对象数据:在
onBindViewHolder中,直接从传入的request对象中获取所需的volunteerId和organizationId,避免依赖全局变量。 - 简化Firestore操作逻辑:不需要通过查询获取文档ID,直接用当前Item的快照ID执行删除操作。
修正后的代码
public class RequestAdapter extends FirestoreRecyclerAdapter<Request, RequestAdapter.ViewHolder> { private ArrayList<Volunteer> mVolunteer = new ArrayList<>(); FirebaseFirestore mFirestore = FirebaseFirestore.getInstance(); public RequestAdapter(@NonNull FirestoreRecyclerOptions<Request> options){ super(options); } @Override protected void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull Request request) { holder.txtNameSurname.setText(request.getFullName()); holder.txtStatusRequest.setText("Solicitud pendiente de aceptación"); holder.txtDateRequest.setText(request.getDate()); // 获取当前Item对应的Firestore文档ID final String pendingDocId = getSnapshots().getSnapshot(position).getId(); final String volunteerId = request.getVolunteerId(); final String organizationId = request.getOrganizationId(); holder.btnOk.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 更新组织的志愿者列表 DocumentReference volunteerRef = mFirestore.collection("organizations").document(organizationId); volunteerRef.update("volunteers", FieldValue.arrayUnion(volunteerId)); // 更新志愿者的组织ID DocumentReference organizationsRef = mFirestore.collection("volunteers").document(volunteerId); organizationsRef.update("organizationId", organizationId); // 删除当前待处理请求文档 mFirestore.collection("pendingVolunteerRequests").document(pendingDocId) .delete() .addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { // 可添加成功后的提示逻辑 } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // 可添加失败后的提示逻辑 } }); } }); holder.btnNoOk.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 直接删除当前待处理请求文档,无需查询 mFirestore.collection("pendingVolunteerRequests").document(pendingDocId) .delete() .addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { // 可添加成功后的提示逻辑 } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // 可添加失败后的提示逻辑 } }); } }); } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) { View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.pending_request, viewGroup, false); return new ViewHolder(view); } public class ViewHolder extends RecyclerView.ViewHolder{ TextView txtNameSurname; TextView txtDateRequest; TextView txtStatusRequest; Button btnOk; Button btnNoOk; public ViewHolder(@NonNull View itemView){ super(itemView); txtNameSurname = itemView.findViewById(R.id.txtNameSurname); txtDateRequest = itemView.findViewById(R.id.txtDate); txtStatusRequest = itemView.findViewById(R.id.txtStatus); btnOk = itemView.findViewById(R.id.btnAccept); btnNoOk = itemView.findViewById(R.id.btnDecline); } } }
关键说明
- 利用
getSnapshots().getSnapshot(position).getId()直接获取当前Item对应的Firestore文档ID,避免了异步查询带来的时序问题和数据覆盖问题。 - 将
volunteerId、organizationId、pendingDocId定义为onBindViewHolder内的局部变量,确保每个Item的点击事件使用的是自身对应的数据。 - 简化了Reject按钮的逻辑,直接删除当前Item对应的文档,无需再次查询,提升了效率并避免误删其他请求。
内容的提问来源于stack exchange,提问作者Joaquin Poggio
相关产品推荐
相关产品推荐

