Android项目中Firestore判断用户是否为Trainer的方法失效排查
问题描述
我有一个Android Studio项目,包含trainers和trainees两个Firestore用户集合,用户邮箱作为两个集合的文档ID,且每个用户仅属于其中一个集合。我需要实现一个方法,接收用户邮箱字符串作为输入,若用户是trainer则返回true,否则返回false(即用户是trainee)。但我写的方法始终返回false,哪怕用户确实是trainer,请问哪里错了?有没有更优的实现方式?
我的代码如下:
public static boolean isTrainer(String email) { FirebaseFirestore firestore = FirebaseFirestore.getInstance(); DocumentReference trainerRef = firestore.collection("trainers").document(email); DocumentReference traineeRef = firestore.collection("trainees").document(email); // Check if the trainer document exists Task<DocumentSnapshot> trainerTask = trainerRef.get(); boolean isTrainer = trainerTask.isSuccessful() && trainerTask.getResult().exists(); // Check if the trainee document exists Task<DocumentSnapshot> traineeTask = traineeRef.get(); boolean isTrainee = traineeTask.isSuccessful() && traineeTask.getResult().exists(); // If the trainer document exists but the trainee document doesn't, the user is a trainer Log.d("FirestoreExample", "isTrainer: " + isTrainer + ", isTrainee: " + isTrainee); return isTrainer && !isTrainee; }
我尝试了多种方法但都无效。
问题根源
Firestore的get()是异步网络请求,你直接调用trainerTask.isSuccessful()时,请求还没完成,此时trainerTask的状态是未完成,isSuccessful()会返回false,导致最终结果一直为false。同步方法无法直接获取异步操作的结果,这是核心问题。
修复方案与优化
由于Firebase操作天生异步,不能用同步方法直接返回布尔值,下面是两种实用的实现方式:
方式1:Java回调接口实现
定义回调接口,在异步任务完成后返回结果,同时优化请求次数(只需查trainers集合即可,因为用户仅属于一个集合):
// 定义回调接口 public interface TrainerCheckCallback { void onResult(boolean isTrainer); } public static void isTrainer(String email, TrainerCheckCallback callback) { FirebaseFirestore firestore = FirebaseFirestore.getInstance(); DocumentReference trainerRef = firestore.collection("trainers").document(email); trainerRef.get().addOnCompleteListener(task -> { if (task.isSuccessful()) { // 只要trainers集合存在该文档,就是trainer callback.onResult(task.getResult().exists()); } else { // 请求失败时默认返回false,可根据需求调整错误处理逻辑 callback.onResult(false); Log.e("FirestoreError", "Check trainer failed", task.getException()); } }); }
调用示例:
isTrainer("user@example.com", isTrainer -> { if (isTrainer) { // 执行trainer相关逻辑 } else { // 执行trainee相关逻辑 } });
方式2:Kotlin协程实现(项目支持Kotlin时)
用await()将异步操作转为同步写法,代码更简洁:
suspend fun isTrainer(email: String): Boolean { val firestore = FirebaseFirestore.getInstance() return try { val snapshot = firestore.collection("trainers").document(email).get().await() snapshot.exists() } catch (e: Exception) { Log.e("FirestoreError", "Check trainer failed", e) false } }
调用时需在协程作用域内执行:
lifecycleScope.launch { val isTrainer = isTrainer("user@example.com") // 处理结果逻辑 }
额外优化建议
- 减少网络请求:无需同时查询两个集合,利用用户仅属于一个集合的规则,只查
trainers即可。 - 错误处理:添加日志记录请求失败的原因,方便排查问题。
- 本地缓存:如果频繁调用该方法,可将用户类型缓存到
SharedPreferences或本地数据库,避免重复请求Firestore,提升响应速度。
内容的提问来源于stack exchange,提问作者Raz Dar
相关产品推荐
相关产品推荐

