Android Firestore仓库模式改造:将Task<DocumentSnapshot>转为Task<User>
实现Firestore仓库类的Task转换方案
你的需求很清晰——把Firestore的数据交互完全封装在UserRepository里,让上层只处理User对象而不是DocumentSnapshot,而且要保持异步非阻塞的特性,这完全可以通过Firebase Task API的链式处理来实现,不需要任何同步操作。
先回顾下你的现有代码:
原UserRepository代码
public class UserRepository { private static final String TAG = "UserRepository"; private FirebaseFirestore db = FirebaseFirestore.getInstance(); private CollectionReference usersRef = db.collection("users"); public Task<DocumentSnapshot> get(String email) { DocumentReference docRef = usersRef.document(email); // Users are referenced by email Log.d(TAG, "Checking DocumentReference exists for: " + email); return docRef.get(); } }
原MainActivity调用代码
final UserRepository userRepository = new UserRepository(); userRepository.get(currentUser.getEmail()).addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() { @Override public void onSuccess(DocumentSnapshot documentSnapshot) { Log.d(TAG, "DocumentSnapshot got"); // Do something with user } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Log.d(TAG, "Could not get DocumentReference", e); } });
修改后的UserRepository实现
我们可以用Firebase Task提供的continueWith方法,在原Task<DocumentSnapshot>完成后,异步将结果转换为User对象,最终返回Task<User>:
public class UserRepository { private static final String TAG = "UserRepository"; private FirebaseFirestore db = FirebaseFirestore.getInstance(); private CollectionReference usersRef = db.collection("users"); public Task<User> get(String email) { DocumentReference docRef = usersRef.document(email); Log.d(TAG, "Checking DocumentReference exists for: " + email); // 链式处理Task,将DocumentSnapshot转换为User return docRef.get().continueWith(new Continuation<DocumentSnapshot, User>() { @Override public User then(@NonNull Task<DocumentSnapshot> task) throws Exception { if (task.isSuccessful()) { DocumentSnapshot document = task.getResult(); if (document.exists()) { // 利用Firestore的toObject方法直接转换为User POJO return document.toObject(User.class); } else { Log.d(TAG, "No user document found for email: " + email); // 文档不存在时返回null,你也可以根据业务需求抛出自定义异常 return null; } } else { // 将原任务的异常传递给下游,确保调用方能捕获到错误 throw task.getException(); } } }); } }
修改后的MainActivity调用
现在你可以直接在Activity中处理User对象,完全不需要关心Firestore的底层细节:
final UserRepository userRepository = new UserRepository(); userRepository.get(currentUser.getEmail()).addOnSuccessListener(new OnSuccessListener<User>() { @Override public void onSuccess(User user) { Log.d(TAG, "User data retrieved"); if (user != null) { // 处理User对象的业务逻辑 } else { // 处理用户不存在的情况 } } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Log.d(TAG, "Failed to fetch user data", e); // 处理获取失败的情况 } });
核心思路说明
- 全程都是异步非阻塞的:
continueWith会在原docRef.get()任务完成后自动执行,不会阻塞主线程 - 完美实现关注点分离:Repository负责Firestore交互和数据转换,Activity只处理业务和UI逻辑
- 异常传递完整:如果原任务失败,我们通过
throw task.getException()把异常传递下去,调用方的addOnFailureListener能正常捕获到错误 - 文档不存在的情况可以灵活处理:你可以返回null,也可以抛出自定义异常,完全根据你的业务需求调整
内容的提问来源于stack exchange,提问作者NiPfi
相关产品推荐
相关产品推荐

