问题描述
我的应用程序中有评论功能,用户可以在此评论彼此的帖子,也可以喜欢或不喜欢彼此的评论。另外,如果他们对自己的评论不满意,可以将其删除。一切正常,直到删除注释部分为止,因为然后我调用notifyDataSetChanged();
或notifyItemRangeChanged();
,并且一切都搞砸了,因为当注释列表刷新时,我尝试喜欢列表中,有时不止一个被喜欢,或者如果我单击不喜欢,有时不止一个被喜欢,有时喜欢和不喜欢最终都被选中。
我实际上尝试了千种方法来修复它,但没有任何效果。下面,我将向您展示一些我尝试过的事情的示例。在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));
}
}
// ...
}