Firestore获取文档名存入List复用 代码返回空值问题排查
问题根因
代码返回空列表的核心原因是误用了Firestore的异步API:
- Firestore的
get()是异步网络请求,调用后不会阻塞当前线程等待结果返回,代码会直接执行到return docunames语句 - 此时请求还未完成,
onSuccess回调还没触发,往docunames里添加文档ID的逻辑根本没有执行,自然返回空列表 - 等请求真正完成、
onSuccess里的代码执行时,方法早已把空列表返回,后续往列表添加数据也无法被方法返回值的调用方及时获取。
另外原代码存在两个额外问题:
- 方法名拼写错误:
getDomumentName应为getDocumentName onFailure是空实现,请求出错时没有任何日志或提示,会大幅提升问题排查难度
正确实现方案
异步API无法直接通过return返回加载结果,需要通过回调机制在数据就绪时传递结果,实现步骤如下:
1. 定义加载结果回调接口
新建回调接口用来接收加载成功/失败的结果:
public interface DocNamesLoadCallback { void onLoadSuccess(List<String> docNames); void onLoadFailed(Exception e); }
2. 改造工具类方法
修改DocumentName类的加载方法,不再直接返回列表,接收回调参数在数据加载完成后回传结果:
public class DocumentName { private final FirebaseFirestore firestore = FirebaseFirestore.getInstance(); public void getDocumentName(DocNamesLoadCallback callback) { firestore.collection("Quizquestions").get() .addOnSuccessListener(queryDocumentSnapshots -> { List<String> docNames = new ArrayList<>(); for (DocumentSnapshot snapshot : queryDocumentSnapshots.getDocuments()) { docNames.add(snapshot.getId()); } // 数据加载完成,通过回调传递结果 callback.onLoadSuccess(docNames); }) .addOnFailureListener(e -> { Log.e("FirestoreErr", "文档名加载失败", e); callback.onLoadFailed(e); }); } }
3. 调用方法&按需使用
在Activity、Fragment或其他业务逻辑处调用加载方法,拿到结果后可以存在成员变量/单例/ViewModel中,后续需要时直接调用即可:
// 页面的成员变量,用来存储加载完成的文档名列表 private List<String> mDocNames = new ArrayList<>(); // 合适的时机调用加载方法,比如页面onCreate时 private void loadDocNames() { DocumentName loader = new DocumentName(); loader.getDocumentName(new DocNamesLoadCallback() { @Override public void onLoadSuccess(List<String> docNames) { // 拿到结果后赋值给成员变量存储 mDocNames = docNames; // 所有依赖文档列表的逻辑可以在这里触发,比如更新UI、初始化题目逻辑 Toast.makeText(YourActivity.this, "加载完成,共" + docNames.size() + "个文档", Toast.LENGTH_SHORT).show(); } @Override public void onLoadFailed(Exception e) { Toast.makeText(YourActivity.this, "加载失败:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } }); } // 后续其他业务逻辑需要用到文档名时,直接操作mDocNames即可,注意要等加载完成后再调用 private void someBusinessMethod() { if (mDocNames.isEmpty()) { // 列表还没加载完,可以加等待逻辑或者提示加载中 return; } // 这里写正常使用列表的逻辑,比如取第一个文档名 String firstDoc = mDocNames.get(0); }
注意事项
- 所有依赖文档列表的逻辑,要么放在
onLoadSuccess回调中执行,要么增加加载状态判断,避免在列表未加载完成时读取到空值 - 如果需要全局使用该列表,可以把列表存储在全局单例或者ViewModel中,在应用启动时提前触发加载,后续业务代码直接读取即可
内容的提问来源于stack exchange,提问作者Hemanth kumar B R
相关产品推荐
相关产品推荐

