如何从Firebase实时数据库获取匹配通讯录用户并在FirebaseRecyclerAdapter展示
解决思路与实现步骤
好的,我来帮你搞定这个需求!核心思路是先拿到匹配的手机号列表,再精准拉取对应用户的完整信息,结合Firebase Realtime Database的特性,我会给你两种可行方案,按需选择:
第一步:先修正匹配逻辑(拿到正确的手机号列表)
你现有的findSignedUpContacts返回的是联系人姓名,但我们需要的是通讯录中已注册Firebase的用户手机号,所以先调整方法:
// 获取通讯录中存在的Firebase用户手机号列表 private List<String> getMatchedPhoneNumbers(Map<String, String> contactsStored, List<String> firebaseNumbers) { List<String> matchedNumbers = new ArrayList<>(); // 先统一手机号格式(避免+号、空格等格式差异导致匹配失败) for (String firebaseNumber : firebaseNumbers) { String normalizedFirebaseNum = normalizePhoneNumber(firebaseNumber); if (contactsStored.containsKey(normalizedFirebaseNum)) { matchedNumbers.add(firebaseNumber); // 存Firebase里的原始格式,方便后续查询 } } return matchedNumbers; } // 手机号格式归一化工具方法 private String normalizePhoneNumber(String phone) { // 去掉所有非数字和+的字符,保证格式统一 return phone.replaceAll("[^0-9+]", "").trim(); }
方案一:基于现有数据库结构,批量查询用户信息
如果不想改动现有数据库结构,可以通过批量查询获取匹配用户的信息,适合用户量不大的场景:
1. 定义回调接口(用于异步结果传递)
// 用于传递UID列表的回调 public interface UidCallback { void onCallback(List<String> uids); } // 用于传递用户信息列表的回调 public interface UserListCallback { void onCallback(List<Users> users); }
2. 通过匹配手机号获取用户UID
private void getMatchedUserUids(List<String> matchedPhoneNumbers, final UidCallback callback) { List<String> uids = new ArrayList<>(); DatabaseReference usersRef = FirebaseDatabase.getInstance().getReference().child("Users"); int queryCount = 0; final int totalQueries = matchedPhoneNumbers.size(); for (final String phone : matchedPhoneNumbers) { // 按手机号查询对应的用户节点 usersRef.orderByChild("phone_number").equalTo(phone) .addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { if (dataSnapshot.exists()) { // 取第一个匹配的用户UID(手机号应该是唯一的) String uid = dataSnapshot.getChildren().iterator().next().getKey(); uids.add(uid); } queryCount++; if (queryCount == totalQueries) { callback.onCallback(uids); } } @Override public void onCancelled(DatabaseError databaseError) { queryCount++; if (queryCount == totalQueries) { callback.onCallback(uids); } } }); } }
3. 通过UID拉取完整用户信息并展示
private void fetchMatchedUsers(List<String> uids, final UserListCallback callback) { List<Users> userList = new ArrayList<>(); DatabaseReference usersRef = FirebaseDatabase.getInstance().getReference().child("Users"); int queryCount = 0; final int totalQueries = uids.size(); for (final String uid : uids) { usersRef.child(uid).addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { if (dataSnapshot.exists()) { Users user = dataSnapshot.getValue(Users.class); userList.add(user); } queryCount++; if (queryCount == totalQueries) { callback.onCallback(userList); } } @Override public void onCancelled(DatabaseError databaseError) { queryCount++; if (queryCount == totalQueries) { callback.onCallback(userList); } } }); } }
4. 串联所有逻辑,绑定RecyclerView
// 假设你已经拿到本地通讯录的contactsStored(Key是归一化后的手机号,Value是联系人姓名) getContactsFromFirebase(new MyCallback() { @Override public void onCallback(List<String> firebaseNumbers) { // 1. 获取匹配的手机号列表 List<String> matchedPhones = getMatchedPhoneNumbers(contactsStored, firebaseNumbers); // 2. 获取对应的用户UID列表 getMatchedUserUids(matchedPhones, new UidCallback() { @Override public void onCallback(List<String> uids) { // 3. 获取完整用户信息 fetchMatchedUsers(uids, new UserListCallback() { @Override public void onCallback(List<Users> users) { // 4. 绑定RecyclerView展示 RecyclerView recyclerView = findViewById(R.id.rv_contacts); recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this)); ContactsAdapter adapter = new ContactsAdapter(users); recyclerView.setAdapter(adapter); } }); } }); } });
5. 普通RecyclerView适配器示例
public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ContactViewHolder> { private List<Users> mUserList; public ContactsAdapter(List<Users> userList) { mUserList = userList; } @NonNull @Override public ContactViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_contact, parent, false); return new ContactViewHolder(itemView); } @Override public void onBindViewHolder(@NonNull ContactViewHolder holder, int position) { Users user = mUserList.get(position); holder.tvName.setText(user.getName()); holder.tvStatus.setText(user.getStatus()); // 用Glide加载头像示例 Glide.with(holder.itemView.getContext()) .load(user.getImage()) .placeholder(R.drawable.default_avatar) .into(holder.ivAvatar); } @Override public int getItemCount() { return mUserList.size(); } static class ContactViewHolder extends RecyclerView.ViewHolder { TextView tvName, tvStatus; ImageView ivAvatar; public ContactViewHolder(@NonNull View itemView) { super(itemView); tvName = itemView.findViewById(R.id.tv_contact_name); tvStatus = itemView.findViewById(R.id.tv_contact_status); ivAvatar = itemView.findViewById(R.id.iv_contact_avatar); } } }
方案二:优化数据库结构(推荐,更高效)
如果用户量较大,批量查询会有性能问题,建议添加反向索引节点,直接通过手机号映射到用户UID:
1. 注册时同步写入反向索引
用户注册成功后,除了写入Users节点,还要写入PhoneNumbers节点:
// 假设user是当前注册用户对象,uid是Firebase Auth生成的用户ID FirebaseDatabase.getInstance().getReference().child("Users").child(uid).setValue(user); // 新增反向索引:手机号为Key,UID为Value FirebaseDatabase.getInstance().getReference().child("PhoneNumbers") .child(user.getPhone_number()).setValue(uid);
2. 简化UID查询逻辑
有了反向索引,获取UID的代码会更高效:
private void getMatchedUserUids(List<String> matchedPhoneNumbers, final UidCallback callback) { List<String> uids = new ArrayList<>(); DatabaseReference phoneRef = FirebaseDatabase.getInstance().getReference().child("PhoneNumbers"); int queryCount = 0; final int totalQueries = matchedPhoneNumbers.size(); for (final String phone : matchedPhoneNumbers) { phoneRef.child(phone).addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { if (dataSnapshot.exists()) { String uid = dataSnapshot.getValue(String.class); uids.add(uid); } queryCount++; if (queryCount == totalQueries) { callback.onCallback(uids); } } @Override public void onCancelled(DatabaseError databaseError) { queryCount++; if (queryCount == totalQueries) { callback.onCallback(uids); } } }); } }
后续的用户信息拉取和RecyclerView绑定逻辑和方案一完全一致。
关于实时更新的补充
如果需要实时监听用户信息变化(比如状态、头像更新),可以把addListenerForSingleValueEvent换成addValueEventListener,并在回调中更新列表数据,然后调用adapter.notifyItemChanged(position)来刷新UI,注意要在页面销毁时移除所有监听,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Panther007
相关产品推荐
相关产品推荐

