删除/删除列表中的注释后,ArrayList中的注释变得混乱

问题描述

我的应用程序中有评论功能用户可以在此评论彼此的帖子,也可以喜欢或不喜欢彼此的评论。另外,如果他们对自己的评论不满意,可以将其删除。一切正常,直到删除注释部分为止,因为然后我调用notifyDataSetChanged();notifyItemRangeChanged();,并且一切都搞砸了,因为当注释列表刷新时,我尝试喜欢列表中,有时不止一个被喜欢,或者如果我单击不喜欢,有时不止一个被喜欢,有时喜欢和不喜欢最终都被选中。

enter image description here

我实际上尝试了千种方法来修复它,但没有任何效果。下面,我将向您展示一些我尝试过的事情的示例。在onChildRemoved();中。我已经这样尝试过了:

评论活动

private void readComments() {
        DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Comments").child(mPostId);
        ChildEventListener childEventListener = new ChildEventListener() {
            @Override
            public void onChildAdded(@NonNull DataSnapshot dataSnapshot,@Nullable String s) {
                Comment comment = dataSnapshot.getValue(Comment.class);
                comment.setComment(comment.getComment());
                mCommentList.add(comment);
                keysList.add(dataSnapshot.getKey());
                mCommentAdapter.notifyItemInserted(mCommentList.size() - 1);
            }

            @Override
            public void onChildChanged(@NonNull DataSnapshot dataSnapshot,@Nullable String s) {

            }

            @Override
            public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
                mCommentAdapter.removeComment(dataSnapshot.getKey());
                mRecyclerView.setAdapter(mCommentAdapter);
                mCommentAdapter.notifyDataSetChanged();
            }

            @Override
            public void onChildMoved(@NonNull DataSnapshot dataSnapshot,@Nullable String s) {

            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        };

        reference.addChildEventListener(childEventListener);
    }

            @Override
            public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
                int index = keysList.indexOf(dataSnapshot.getKey());
                mCommentList.remove(index);
                mCommentAdapter.notifyItemChanged(index);
                keysList.remove(index);
                mCommentAdapter.notifyItemRangeChanged(index,mCommentList.size());
            }

        @Override
        public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
            index = keysList.indexOf(dataSnapshot.getKey());
            keysList.remove(index);
            mCommentList.remove(index);
            mCommentAdapter.notifyDataSetChanged();
        }

并且列表继续。我已经尝试了多种变体,但仍然删除评论后,当我尝试喜欢或不喜欢列表中的评论时,就会有多个人喜欢或不喜欢,有时最终还是喜欢和不喜欢。

关于可能是什么原因的想法?

CommentAdapter (我喜欢和不喜欢评论的方式)

public class CommentAdapter extends RecyclerView.Adapter<CommentAdapter.ViewHolder> {

    private Context mContext;
    private List<Comment> mCommentList;

    private String mPostId;
    private String mNotificationId;

    private FirebaseUser mFirebaseUser;

    public CommentAdapter(Context mContext,List<Comment> mComment,String mPostId) {
        this.mContext = mContext;
        this.mCommentList = mComment;
        this.mPostId = mPostId;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.comment_item,parent,false);

        return new CommentAdapter.ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull final ViewHolder holder,int position) {

        mFirebaseUser = FirebaseAuth.getInstance().getCurrentUser();
        final Comment comment = mCommentList.get(position);

        holder.comment.setText(comment.getComment());

        commentLike(comment.getCommentid(),holder.commentLike);
        commentdislike(comment.getCommentid(),holder.commentdislike);
        getUserInfo(holder.image_profile,holder.username,comment.getPublisher());
        commentLikesNumber(holder.commentLikesNumber,comment.getCommentid());
        commentdislikesNumber(holder.commentdislikesNumber,comment.getCommentid());
        commentResponseNumber(holder.commentResponseNumber,comment.getCommentid());

        holder.iconComment.setonClickListener(v -> {
            Intent intent = new Intent(mContext,ResponseActivity.class);
            intent.putExtra("commentid",comment.getCommentid());
            intent.putExtra("publisherid",comment.getPublisher());
            intent.putExtra("postid",mPostId);
            mContext.startActivity(intent);
        });

        holder.commentLike.setonClickListener(v -> {
            if (holder.commentLike.getTag().equals("like") && holder.commentdislike.getTag().equals("dislike")) {
                likeComment(comment.getCommentid(),mPostId,comment.getPublisher());
            } else if (holder.commentLike.getTag().equals("like") && holder.commentdislike.getTag().equals("disliked")) {
                likeComment(comment.getCommentid(),comment.getPublisher());
                removedislike(comment.getCommentid());
            } else {
                removeLike(comment.getPublisher(),comment.getCommentid());
            }
        });

        holder.commentdislike.setonClickListener(v -> {
            if (holder.commentdislike.getTag().equals("dislike") && holder.commentLike.getTag().equals("like")) {
                dislikeComment(comment.getCommentid());
                Toast.makeText(mContext,"Don't be mean",Toast.LENGTH_SHORT).show();
            } else if (holder.commentdislike.getTag().equals("dislike") && holder.commentLike.getTag().equals("liked")) {
                dislikeComment(comment.getCommentid());
                removeLike(comment.getPublisher(),comment.getCommentid());
                Toast.makeText(mContext,Toast.LENGTH_SHORT).show();
            } else {
                removedislike(comment.getCommentid());
            }
        });

        holder.image_profile.setonClickListener(v -> {
            Intent intent = new Intent(mContext,MainActivity.class);
            intent.putExtra("publisherid",comment.getPublisher());
            mContext.startActivity(intent);
        });

        //Timestamp to Date
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        Date date = new Date(timestamp.getTime());

        //Current timestamp
        Calendar calendar = Calendar.getInstance();
        long ts = calendar.getTimeInMillis();

        //Getting comment timestamp from database
        long timestampOfComment = comment.getTimestamp();

        //SECOND WAY

        long duration = ts - timestampOfComment;

        long diffInSeconds = TimeUnit.MILLISECONDS.toSeconds(duration);
        long diffInMinutes = TimeUnit.MILLISECONDS.toMinutes(duration);
        long diffInHours = TimeUnit.MILLISECONDS.toHours(duration);
        long diffInDays = TimeUnit.MILLISECONDS.toDays(duration);

        if (diffInSeconds < 10) {
            holder.timestamp.setText(" \u25CF " + "Just Now");
        } else if (diffInSeconds > 10 && diffInSeconds < 60) {
            holder.timestamp.setText(" \u25CF " + diffInSeconds + " seconds ago");
        } else if (diffInSeconds > 60 && diffInMinutes == 1) {
            holder.timestamp.setText(" \u25CF " + diffInMinutes + " minute ago");
        } else if (diffInSeconds > 60 && diffInMinutes < 60) {
            holder.timestamp.setText(" \u25CF " + diffInMinutes + " minutes ago");
        } else if (diffInSeconds > 60 && diffInMinutes > 60 && diffInHours == 1) {
            holder.timestamp.setText(" \u25CF " + diffInHours + " hour ago");
        } else if (diffInSeconds > 60 && diffInMinutes > 60 && diffInHours > 1 && diffInHours < 24) {
            holder.timestamp.setText(" \u25CF " + diffInHours + " hours ago");
        } else if (diffInSeconds > 60 && diffInMinutes > 60 && diffInHours > 24 && diffInDays == 1) {
            holder.timestamp.setText(" \u25CF " + diffInDays + " day ago");
        } else if (diffInSeconds > 60 && diffInMinutes > 60 && diffInHours > 24 && diffInDays > 1) {
            holder.timestamp.setText(" \u25CF " + diffInDays + " days ago");
        }

        holder.itemView.setonLongClickListener(v -> {
            if (comment.getPublisher().equals(mFirebaseUser.getUid())) {
                AlertDialog alertDialog = new AlertDialog.Builder(mContext).create();
                alertDialog.setTitle("Would you like to delete this comment?");
                alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL,"No",(dialog,which) -> dialog.dismiss());
                alertDialog.setButton(AlertDialog.BUTTON_POSITIVE,"Yes",which) -> {
                    deleteCommentNotification(mPostId,comment.getCommentid());
                    FirebaseDatabase.getInstance().getReference("Comments Liked").child(comment.getCommentid()).setValue(null);
                    FirebaseDatabase.getInstance().getReference("Comments disliked").child(comment.getCommentid()).setValue(null);
                    FirebaseDatabase.getInstance().getReference("Responses").child(comment.getCommentid()).setValue(null);
                    Toast.makeText(mContext,"Your comment has been deleted.",Toast.LENGTH_SHORT).show();
                    dialog.dismiss();
                });
                alertDialog.show();
            }
            return true;
        });
    }

    @Override
    public int getItemCount() {
        if (mCommentList != null) {
            return mCommentList.size();
        } else {
            return 0;
        }
    }

    static class ViewHolder extends RecyclerView.ViewHolder {

        CircleImageView image_profile;
        TextView username,comment,commentLikesNumber,commentdislikesNumber,commentResponseNumber,timestamp;
        ImageView commentLike,commentdislike,iconComment;

        ViewHolder(@NonNull View itemView) {
            super(itemView);

            image_profile = itemView.findViewById(R.id.image_profile);
            comment = itemView.findViewById(R.id.comment);
            username = itemView.findViewById(R.id.username);
            commentLike = itemView.findViewById(R.id.icon_thumb_up_grey);
            commentdislike = itemView.findViewById(R.id.icon_thumb_down_grey);
            commentLikesNumber = itemView.findViewById(R.id.comment_likes_number);
            commentdislikesNumber = itemView.findViewById(R.id.comment_dislikes_number);
            iconComment = itemView.findViewById(R.id.icon_comment_grey);
            commentResponseNumber = itemView.findViewById(R.id.comment_response_number);
            timestamp = itemView.findViewById(R.id.timestamp);
        }
    }

    private void deleteCommentNotification(String postid,String commentid) {
        DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("Comments").child(postid).child(commentid);
        reference.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                if (dataSnapshot.exists()) {
                    String notificationId = dataSnapshot.child("notificationId").getValue(String.class);
                    String user = dataSnapshot.child("for").getValue(String.class);
                    if (notificationId != null && user != null) {
                        FirebaseDatabase.getInstance().getReference("Notifications").child(user).child(notificationId).removeValue();
                        reference.removeValue();
                    }
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }

    private void getUserInfo(final ImageView prof_image,final TextView username,String publisherid) {
        DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("Users").child(publisherid);
        reference.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                User user = dataSnapshot.getValue(User.class);
                if (user != null) {
                    Glide.with(mContext.getApplicationContext()).load(user.getimageurl()).into(prof_image);
                    username.setText(user.getUsername());
                } else {
                    prof_image.setimageResource(R.drawable.profile_placeholder);
                    username.setVisibility(View.GONE);
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }

    public void removeComment(final String key) {
        for (int i = 0; i < mCommentList.size(); i++) {
            if (mCommentList.get(i).getCommentid().equals(key)) {
                mCommentList.remove(i);
                break;
            }
        }
    }

    private void commentLike(final String commentid,final ImageView imageView) {
        DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("Comments Liked").child(commentid);
        reference.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                if (mFirebaseUser != null)
                    if (dataSnapshot.child(mFirebaseUser.getUid()).exists()) {
                        imageView.setimageResource(R.drawable.ic_thumb_up_blue);
                        imageView.setTag("liked");
                    } else {
                        imageView.setimageResource(R.drawable.ic_thumb_up_grey);
                        imageView.setTag("like");
                    }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }

    private void commentdislike(final String commentid,final ImageView imageView) {
        DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("Comments disliked").child(commentid);
        reference.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                if (mFirebaseUser != null)
                    if (dataSnapshot.child(mFirebaseUser.getUid()).exists()) {
                        imageView.setimageResource(R.drawable.ic_thumb_down_blue);
                        imageView.setTag("disliked");
                    } else {
                        imageView.setimageResource(R.drawable.ic_thumb_down_grey);
                        imageView.setTag("dislike");
                    }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }

    private void commentLikesNumber(TextView commentLikesNumber,String commentid) {
        DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("Comments Liked").child(commentid);
        reference.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                long commentLikes = dataSnapshot.getChildrenCount();
                if (commentLikes == 0) {
                    commentLikesNumber.setVisibility(View.INVISIBLE);
                } else {
                    commentLikesNumber.setVisibility(View.VISIBLE);
                    commentLikesNumber.setText(String.valueOf(commentLikes));
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }

    private void commentdislikesNumber(TextView commentdislikesNumber,String commentid) {
        DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("Comments disliked").child(commentid);
        reference.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                long commentdislikes = dataSnapshot.getChildrenCount();
                if (commentdislikes == 0) {
                    commentdislikesNumber.setVisibility(View.INVISIBLE);
                } else {
                    commentdislikesNumber.setVisibility(View.VISIBLE);
                    commentdislikesNumber.setText(String.valueOf(commentdislikes));
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }

    private void commentResponseNumber(TextView commentResponseNumber,String commentid) {
        DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("Responses").child(commentid);
        reference.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                long commentResponses = dataSnapshot.getChildrenCount();
                if (commentResponses == 0) {
                    commentResponseNumber.setVisibility(View.INVISIBLE);
                } else {
                    commentResponseNumber.setVisibility(View.VISIBLE);
                    commentResponseNumber.setText(String.valueOf(commentResponses));
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }

    private void likeComment(String commentId,String postId,String userId) {
        DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("Comments Liked").child(commentId).child(mFirebaseUser.getUid());

        mNotificationId = reference.push().getKey();

        HashMap<String,Object> hashMap = new HashMap<>();
        hashMap.put("notificationId",mNotificationId);
        hashMap.put("commentid",commentId);
        hashMap.put("userid",mFirebaseUser.getUid());

        reference.setValue(hashMap);

        HashMap<String,Object> hashMap1 = new HashMap<>();
        hashMap1.put("userid",mFirebaseUser.getUid());
        hashMap1.put("comment","liked your comment");
        hashMap1.put("postid",postId);
        hashMap1.put("ispost",true);
        hashMap1.put("notificationId",mNotificationId);
        hashMap1.put("commentid",commentId);
        hashMap1.put("seen",false);
        hashMap1.put("type","");

        if (!mFirebaseUser.getUid().equals(userId)) {
            FirebaseDatabase.getInstance().getReference("Notifications").child(userId).child(mNotificationId).setValue(hashMap1);
        }
    }

    private void removeLike(String userId,String commentId) {
        DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Comments Liked").child(commentId).child(mFirebaseUser.getUid());
        reference.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                if (dataSnapshot.exists()) {
                    String notificationId = dataSnapshot.child("notificationId").getValue(String.class);
                    if (notificationId != null) {
                        FirebaseDatabase.getInstance().getReference("Notifications").child(userId).child(notificationId).removeValue();
                        reference.removeValue();
                    }
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }

    private void dislikeComment(String commentId) {
        DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Comments disliked").child(commentId).child(mFirebaseUser.getUid());

        HashMap<String,Object> hashMap = new HashMap<>();
        hashMap.put("commentid",commentId);
        hashMap.put("notificationId",mNotificationId);
        hashMap.put("userid",mFirebaseUser.getUid());

        reference.setValue(hashMap);
    }

    private void removedislike(String commentId) {
        DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Comments disliked").child(commentId).child(mFirebaseUser.getUid());
        reference.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                reference.removeValue();
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }
}

解决方法

发生这种怪异行为的原因是您在每次ValueEventListener的调用中注册了onBindViewHolder个对象。每当新项目滚动到视图中或更改其数据时,都会调用onBindViewHolder方法。由于您从未注销过监听器,因此即使它们可能已经绑定到其他项目,它们也会继续更新视图。

请勿在{{1​​}}中注册任何侦听器。使用适配器设置onBindViewHolder,并在不再使用适配器时注销它们。在侦听器内,调用适配器的notify方法,而不是直接更新视图。将OnClickListeners的注册移到您的ViewHolder中,并使它们通用,这样它们就不会绑定到特定项目。 ValueEventListener应该只是更新您的视图。

所有更改都可以解决您的问题,并使滚动更加流畅;-)

CommentAdapter

onBindViewHolder

ViewHolder

public class CommentAdapter extends RecyclerView.Adapter<CommentAdapter.ViewHolder> {

private Context mContext;
private List<Comment> mCommentList;

private String mPostId;
private String mNotificationId;

private FirebaseUser mFirebaseUser;

public CommentAdapter(Context mContext,List<Item> items,String mPostId) {
  this.items = items;
  this.mPostId = mPostId;
}

@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,int viewType) {
  View view = LayoutInflater.from(mContext).inflate(R.layout.comment_item,parent,false);
  return new CommentAdapter.ViewHolder(mContext,mPostId,view);
}

@Override
public void onBindViewHolder(@NonNull final ViewHolder holder,int position) {

  holder.update(items.get(position));
  
}

活动

public static class ViewHolder extends RecyclerView.ViewHolder {

private Item item;

public ViewHolder(Context context,String mPostId,View itemView) {  
        super(itemView);  
        
        // ...
    
        // Register OnClickListeners here once for the view. Example:
        icon.setOnClickListener(v -> {
        
          if (item != null) {
              Comment comment = item.getComment();
              Intent intent = new Intent(mContext,ResponseActivity.class);
              intent.putExtra("commentid",comment.getCommentid());
              intent.putExtra("publisherid",comment.getPublisher());
              intent.putExtra("postid",mPostId);
              mContext.startActivity(intent);
          }
        });
        
       // ...
    }

public void update(Item item) {
    this.item = item;
    update(item.getComment());
    update(item.getLikeStatus());
}

public void update(Comment comment) {
    textControl.setText(comment.getText());
    // ...
}

public void update(LikeStatus status) {
    
    if (status.likes == 0) {
      likeNumbersText.setVisibility(View.INVISIBLE);
    } else {
      likeNumbersText.setVisibility(View.VISIBLE);
      likeNumbersText.setText(String.valueOf(likes));
    }
    
    if (status.dislikes == 0) {
      dislikeNumbersText.setVisibility(View.INVISIBLE);
    } else {
      dislikeNumbersText.setVisibility(View.VISIBLE);
      dislikesNumbersText.setText(String.valueOf(likes));
    }
  }
    // ...
}