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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:14:52