将Realtime Database的addListenerForSingleValueEvent转换为Cloud Firestore
我来帮你搞定从Firebase Realtime Database到Cloud Firestore的迁移适配,你问到的两个点刚好是迁移里最核心的部分:
DatabaseReference是什么? 在Realtime Database里,DatabaseReference指向的是数据库中的某个树形节点;而Cloud Firestore采用的是文档-集合的层级结构,对应的引用分为两种:
CollectionReference:指向一个集合(可以理解为Realtime里存放多个子节点的父节点)DocumentReference:指向单个文档(对应Realtime里的单个子节点)
你已经完成了初始化代码的替换,把FirebaseDatabase和DatabaseReference换成了FirebaseFirestore db,接下来只需要根据你的数据结构定义具体的引用就行。比如如果原来的myRef是指向用户数据的根节点,那在Firestore里可以这么写:
// 指向users集合(对应原来的用户根节点) private CollectionReference usersRef = db.collection("users"); // 或者指向当前登录用户的专属文档 private DocumentReference currentUserDocRef = db.collection("users").document(user.getUid());
myRef.addListenerForSingleValueEvent方法? Realtime里的addListenerForSingleValueEvent是用来单次读取数据(读取一次后就不再监听变化),在Firestore里对应的是get()方法,它返回一个Task对象,你可以通过添加OnSuccessListener和OnFailureListener来处理读取结果,逻辑和原来的监听完全对应。
结合你提供的代码,修改后的完整逻辑大概是这样:
首先更新变量定义:
// 替换原有的FirebaseDatabase和DatabaseReference private FirebaseFirestore db; // 根据业务需求定义集合引用 private CollectionReference usersRef;
然后修改setupFirebaseAuth方法:
private void setupFirebaseAuth(){ Log.d(TAG, "setupFirebaseAuth: setting up firebase auth."); mAuth = FirebaseAuth.getInstance(); db = FirebaseFirestore.getInstance(); usersRef = db.collection("users"); // 对应原来的myRef指向的用户节点 mAuthListener = new FirebaseAuth.AuthStateListener() { @Override public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { FirebaseUser user = firebaseAuth.getCurrentUser(); if (user != null) { // User is signed in Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid()); // 替换addListenerForSingleValueEvent,用Firestore的get()单次读取数据 usersRef.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() { @Override public void onSuccess(QuerySnapshot querySnapshot) { // 检查用户名是否已存在(需要适配你的checkIfUsernameExists方法) if(firebaseMethods.checkIfUsernameExists(username, querySnapshot)){ // 用Firestore生成的随机ID片段作为后缀,替代原来的push().getKey() String append = db.collection("temp").document().getId().substring(3,10); Log.d(TAG, "onSuccess: username already exists. Appending random string to name: " + append); username = username + append; } // 添加新用户到Firestore数据库 firebaseMethods.addNewUserToFirestore(user.getUid(), username, /* 其他用户字段 */); // 添加用户账户设置到Firestore(比如单独的user_account_settings集合) } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Log.e(TAG, "onFailure: 读取用户数据失败", e); } }); } else { // User is signed out Log.d(TAG, "onAuthStateChanged:signed_out"); } } }; }
另外,你原来的checkIfUsernameExists方法需要适配Firestore的QuerySnapshot,示例修改如下:
// 适配Firestore的用户名检查方法 public boolean checkIfUsernameExists(String username, QuerySnapshot snapshot){ for(QueryDocumentSnapshot doc : snapshot){ // 假设你有一个User实体类,用来映射Firestore文档 User user = doc.toObject(User.class); if(user.getUsername().equals(username)){ return true; } } return false; }
需要注意的是:Firestore的document().getId()生成的随机ID和Realtime的push().getKey()逻辑类似,完全可以用来生成你需要的随机后缀字符串。
内容的提问来源于stack exchange,提问作者Paradox

