You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:08:38