如何按时间排序聊天APP首页RecyclerView的最近会话项?
实现会话按最后消息时间置顶的解决方案
要解决这个问题,核心是把用户信息和对应会话的最后消息时间绑定在一起,再基于时间排序。以下是具体实现步骤:
1. 创建会话包装类
新建ChatSession类,封装用户信息和对应会话的最后消息时间,为排序提供依据:
public class ChatSession { private User user; private long lastMsgTime; public ChatSession(User user, long lastMsgTime) { this.user = user; this.lastMsgTime = lastMsgTime; } // Getter和Setter方法 public User getUser() { return user; } public void setUser(User user) { this.user = user; } public long getLastMsgTime() { return lastMsgTime; } public void setLastMsgTime(long lastMsgTime) { this.lastMsgTime = lastMsgTime; } }
2. 修改HomeActivity的数据结构与查询逻辑
把原有的ArrayList<User>替换为ArrayList<ChatSession>,调整Firebase查询流程,先获取好友列表,再逐个查询每个好友的会话最后消息时间:
// 替换原有的users列表 ArrayList<ChatSession> chatSessions; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityHomeBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); chatSessions = new ArrayList<>(); homeAdapter = new HomeAdapter(this, chatSessions); binding.homeRecyclerView.setAdapter(homeAdapter); FirebaseAuth mAuth = FirebaseAuth.getInstance(); FirebaseDatabase database = FirebaseDatabase.getInstance(); String currentUserId = mAuth.getUid(); // 先获取当前用户的好友ID列表 database.getReference().child("users").child(currentUserId).child("friendList") .addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot friendSnapshot) { chatSessions.clear(); // 遍历每个好友ID for (DataSnapshot friendIdSnapshot : friendSnapshot.getChildren()) { String friendId = friendIdSnapshot.getValue(String.class); if (friendId == null) continue; // 获取好友的User信息 database.getReference().child("users").child(friendId) .addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot userSnapshot) { User user = userSnapshot.getValue(User.class); if (user == null) return; // 构造会话房间ID String senderRoom = currentUserId + user.getUserId(); // 获取该会话的最后消息时间 database.getReference().child("chats").child(senderRoom) .addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot chatSnapshot) { long lastMsgTime = 0; if (chatSnapshot.exists()) { Long tempTime = chatSnapshot.child("lastMsgTime").getValue(Long.class); lastMsgTime = tempTime == null ? 0 : tempTime; } // 添加到会话列表 chatSessions.add(new ChatSession(user, lastMsgTime)); // 排序:按最后消息时间降序,最新会话置顶 Collections.sort(chatSessions, (cs1, cs2) -> Long.compare(cs2.getLastMsgTime(), cs1.getLastMsgTime()) ); homeAdapter.notifyDataSetChanged(); progressDialog.dismiss(); } @Override public void onCancelled(@NonNull DatabaseError error) {} }); } @Override public void onCancelled(@NonNull DatabaseError error) {} }); } } @Override public void onCancelled(@NonNull DatabaseError error) {} }); }
3. 修改HomeAdapter适配ChatSession
将适配器改为接收ArrayList<ChatSession>,从包装类中获取用户信息进行展示:
public class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.HomeViewHolder> { FirebaseAuth mAuth; FirebaseDatabase database; Context context; ArrayList<ChatSession> chatSessions; // 替换原有的users列表 public HomeAdapter(Context context, ArrayList<ChatSession> chatSessions) { this.context = context; this.chatSessions = chatSessions; } @NonNull @Override public HomeViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(context).inflate(R.layout.activity_home_item, parent, false); return new HomeViewHolder(view); } @Override public void onBindViewHolder(@NonNull HomeViewHolder holder, int position) { ChatSession chatSession = chatSessions.get(position); User user = chatSession.getUser(); mAuth = FirebaseAuth.getInstance(); database = FirebaseDatabase.getInstance(); String senderId = mAuth.getUid(); String senderRoom = senderId + user.getUserId(); holder.binding.friendName.setText(user.getName()); Picasso.get().load(user.getProfileImage()).into(holder.binding.friendProfilePic); holder.binding.friend.setOnClickListener(v -> { Intent intent = new Intent(context, ChattingActivity.class); intent.putExtra("userName", user.getName()); intent.putExtra("profilePic", user.getProfileImage()); intent.putExtra("userId", user.getUserId()); intent.putExtra("token", user.getToken()); context.startActivity(intent); }); // 保持原有消息监听逻辑,实时更新最后消息内容与时间 database.getReference().child("chats").child(senderRoom) .addValueEventListener(new ValueEventListener() { @SuppressLint("SetTextI18n") @Override public void onDataChange(@NonNull DataSnapshot snapshot) { if (snapshot.exists()) { String lastMsg = snapshot.child("lastMsg").getValue(String.class); Long time = snapshot.child("lastMsgTime").getValue(Long.class); if (time == null) time = 0L; @SuppressLint("SimpleDateFormat") SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm a"); holder.binding.friendLastMsg.setText(lastMsg); holder.binding.friendLastMsgTime.setText(dateFormat.format(new Date(time))); } else { holder.binding.friendLastMsg.setText("Tap to chat"); holder.binding.friendLastMsgTime.setText(""); } } @Override public void onCancelled(@NonNull DatabaseError error) {} }); } @Override public int getItemCount() { return chatSessions.size(); } protected static class HomeViewHolder extends RecyclerView.ViewHolder { ActivityHomeItemBinding binding; public HomeViewHolder(@NonNull View view) { super(view); binding = ActivityHomeItemBinding.bind(view); } } }
4. 优化说明
- 使用
addListenerForSingleValueEvent替代addValueEventListener,避免重复监听导致的性能问题与数据重复添加 - 包装类
ChatSession实现了用户信息与会话时间的绑定,解决了User类无时间字段的排序难题 - 排序逻辑采用降序,确保最新消息的会话始终排在列表顶部
- 处理了时间字段为空的边界情况,默认设为0,让无会话的好友排在列表末尾
内容的提问来源于stack exchange,提问作者Topu Rayhan Rabby Mamud
相关产品推荐
相关产品推荐

