Java如何从Firebase Firestore的Map类型字段中读取存储数据
Cloud Firestore Map类型字段读取问题(Java Android)
需求说明
需要检索Cloud Firestore中Map类型字段的数据,具体需求为从All Comments字段中获取字符串类型的Comment值,将其展示在TextView控件中,开发使用语言为Java,对应数据库结构参考截图:
已尝试方案
方案1:写入根集合后读取,应用崩溃
写入代码
Map<String,String> allComments=new HashMap<String,String>(); String commentContent=commentboxedittext.getText().toString(); allComments.put("Movie Name",name); allComments.put("Comment",commentContent); firebaseFirestore.collection("All Comments").document("MovieComments").set(allComments, SetOptions.merge());
读取代码
DocumentReference docRef = firebaseFirestore.collection("All Comments").document("MovieComments"); docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() { @Override public void onComplete(@NonNull Task<DocumentSnapshot> task) { if (task.isSuccessful()) { DocumentSnapshot document = task.getResult(); if (document.exists()) { Map<String, Object> m=document.getData(); userComment=m.get("Comment").toString(); mName=m.get("Movie Name").toString(); } else { Toast.makeText(MovieDetails.this, "No Such Document", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(MovieDetails.this, "Error", Toast.LENGTH_SHORT).show(); } } });
执行上述检索代码后应用发生崩溃。
方案2:写入用户文档嵌套字段,写入正常但无对应读取逻辑
该写入方式可正常完成数据存储,但不清楚该嵌套结构下的检索方法,写入代码如下:
Map<String,String> allComments=new HashMap<String,String>(); Map<String, Object> user=new HashMap<String,Object>(); userID=firebaseAuth.getCurrentUser().getUid(); userReference=firebaseFirestore.collection("Users ").document(userID); String commentContent=commentboxedittext.getText().toString(); allComments.put("Movie Name",name); allComments.put("Comment",commentContent); user.put("All Comments",allComments); userReference.set(user, SetOptions.merge()).addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void unused) { Toast.makeText(MovieDetails.this, "Comment Added", Toast.LENGTH_SHORT).show(); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { if(e instanceof FirebaseNetworkException) Toast.makeText(MovieDetails.this, "No Internet Connection", Toast.LENGTH_SHORT).show(); Toast.makeText(MovieDetails.this, "Values Not Stored", Toast.LENGTH_SHORT).show(); } });
解决方案
方案1崩溃原因
- 未做非空判断:
m.get("Comment")如果取到null,直接调用toString()会触发空指针异常 - 路径不匹配:如果实际数据是嵌套存储在用户文档下,读取根集合
All Comments下的文档自然拿不到对应字段,返回null触发崩溃
两种存储结构对应的正确读取代码
情况1:数据存储在根集合All Comments/MovieComments下(对应第一种写入逻辑)
读取时直接调用SDK提供的字段取值方法,增加非空判断即可:
DocumentReference docRef = firebaseFirestore.collection("All Comments").document("MovieComments"); docRef.get().addOnCompleteListener(task -> { if (task.isSuccessful()) { DocumentSnapshot document = task.getResult(); if (document.exists()) { // 直接取指定字段,SDK自动做类型转换,无需先取整个文档Map String userComment = document.getString("Comment"); String mName = document.getString("Movie Name"); // 非空判断后再赋值给TextView if (userComment != null) { commentTextView.setText(userComment); } if (mName != null) { movieNameTextView.setText(mName); } } else { Toast.makeText(MovieDetails.this, "No Such Document", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(MovieDetails.this, "Get Data Failed: " + task.getException().getMessage(), Toast.LENGTH_SHORT).show(); } });
情况2:数据存储在Users集合对应用户文档的All Comments嵌套Map中(对应第二种写入逻辑)
先读取外层嵌套Map,再从Map中取内部字段,同步做非空校验:
String userID = firebaseAuth.getCurrentUser().getUid(); // 注意修正原集合名末尾多余的空格 DocumentReference userDocRef = firebaseFirestore.collection("Users").document(userID); userDocRef.get().addOnCompleteListener(task -> { if (task.isSuccessful()) { DocumentSnapshot document = task.getResult(); if (document.exists()) { // 先取外层的All Comments嵌套字段 Map<String, Object> allCommentsMap = (Map<String, Object>) document.get("All Comments"); if (allCommentsMap != null) { // 从嵌套Map中取目标字段 String userComment = (String) allCommentsMap.get("Comment"); String mName = (String) allCommentsMap.get("Movie Name"); if (userComment != null) { commentTextView.setText(userComment); } if (mName != null) { movieNameTextView.setText(mName); } } } else { Toast.makeText(MovieDetails.this, "User Document Not Exist", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(MovieDetails.this, "Get Data Failed: " + task.getException().getMessage(), Toast.LENGTH_SHORT).show(); } });
注意事项
- 第二种写入代码里的集合名
Users末尾多了一个空格,读取时如果不带空格会找不到文档,建议统一修改为无多余空格的Users - 尽量不要用
getData()获取整个文档Map再拆字段,直接调用getString()、get()等方法取指定字段,SDK会自动处理类型转换,降低类型转换错误概率 - 所有从Firestore取到的对象都要做非空判断,避免字段不存在、文档不存在等场景触发空指针崩溃
内容的提问来源于stack exchange,提问作者Titan Demon
相关产品推荐
相关产品推荐

