为什么从Firebase Realtime Database读取的数据返回null值?
问题现象
尝试获取Firebase Realtime Database中class_password与class_uuid两个子节点的取值时,返回结果始终为null。
实现代码
public class StudentJoinClassDialog { Context context; Dialog dialog; TextInputEditText classCode, classPassword; Button studentJoinClass; String selectedClasscode, selectedClassPass; String checkPassword, checkClassUuid; String TAG = "StudentJoinClassDialog"; public StudentJoinClassDialog(@NonNull Context mContext) { this.context = mContext; dialog = new Dialog(context); } public void showDialog() { dialog.setContentView(R.layout.student_join_class_dialog_layout); dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.R.attr.colorBackground)); dialog.create(); dialog.show(); // IDs // classCode = dialog.findViewById(R.id.enter_class_code_input_edit_text); classPassword = dialog.findViewById(R.id.enter_class_password_inputedittext); studentJoinClass = dialog.findViewById(R.id.join_class_btn); // IDs //** studentJoinClass.setOnClickListener(view -> { selectedClassPass = classPassword.getEditableText().toString().trim(); Log.d(TAG, "class UUID : " + selectedClasscode + " class Password : " + selectedClassPass); Log.d(TAG, "classbook path : " + "classbook " + "/" + selectedClasscode + "/" + "class_information"); FirebaseDatabase .getInstance() .getReference() .child("classbook") .child(classCode.getEditableText().toString().trim()) .child("class_information") .addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { checkClassUuid = snapshot.child("class_uuid").getValue(String.class); checkPassword = snapshot.child("class_password").getValue(String.class); if (selectedClasscode.equals(checkClassUuid) && selectedClassPass.equals(checkPassword)) { Toast.makeText(context, "You are in", Toast.LENGTH_LONG).show(); } else { Toast.makeText(context, "Class does not exist", Toast.LENGTH_SHORT).show(); } } @Override public void onCancelled(@NonNull DatabaseError error) { } }); Log.d(TAG, "Retrieved Class UUID : " + checkClassUuid + " Retrieved Class Password : " + checkPassword); }); } }
运行日志
2021-11-06 20:32:33.409 8071-8071/com.vrs.attendy D/StudentJoinClassDialog: class UUID : null class Password : 123 2021-11-06 20:32:33.409 8071-8071/com.vrs.attendy D/StudentJoinClassDialog: classbook path : classbook /null/class_information 2021-11-06 20:32:33.409 8071-8071/com.vrs.attendy D/StudentJoinClassDialog: Retrieved Class UUID : null Retrieved Class Password : null
问题原因
- 变量
selectedClasscode未完成赋值:点击事件逻辑中仅对selectedClassPass做了取值赋值,没有对班级编码变量selectedClasscode赋值,导致后续校验逻辑中该变量为null,匹配失败。 - 异步操作特性导致外部取值为空:Firebase Realtime Database的查询是异步操作,
addValueEventListener的回调方法onDataChange执行时机晚于外部的同步日志打印代码,所以在回调外部打印checkClassUuid和checkPassword时,回调还未执行,变量自然为null。 - 缺少错误捕获逻辑:
onCancelled方法为空,当出现权限不足、网络异常、节点不存在等问题时无法排查具体错误。
修复方案
- 补充
selectedClasscode赋值逻辑,在点击事件中获取班级密码的代码后增加一行:
selectedClasscode = classCode.getEditableText().toString().trim();
- 所有需要使用查询返回结果的逻辑全部放在
onDataChange回调内部执行,不要在回调外部访问异步返回的变量。 - 增加空校验和错误日志逻辑,避免空指针异常,同时完善
onCancelled方法的错误处理。
修复后核心代码示例
studentJoinClass.setOnClickListener(view -> { selectedClassPass = classPassword.getEditableText().toString().trim(); // 补充班级编码赋值 selectedClasscode = classCode.getEditableText().toString().trim(); // 输入非空校验 if (selectedClasscode.isEmpty() || selectedClassPass.isEmpty()) { Toast.makeText(context, "请填写完整的班级编码和密码", Toast.LENGTH_SHORT).show(); return; } Log.d(TAG, "class UUID : " + selectedClasscode + " class Password : " + selectedClassPass); Log.d(TAG, "classbook path : " + "classbook " + "/" + selectedClasscode + "/" + "class_information"); FirebaseDatabase .getInstance() .getReference() .child("classbook") .child(selectedClasscode) .child("class_information") // 单次查询用addListenerForSingleValueEvent更合适,避免持续监听 .addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { // 先判断节点是否存在 if (!snapshot.exists()) { Toast.makeText(context, "班级不存在", Toast.LENGTH_SHORT).show(); return; } checkClassUuid = snapshot.child("class_uuid").getValue(String.class); checkPassword = snapshot.child("class_password").getValue(String.class); // 空校验避免空指针 if (checkClassUuid == null || checkPassword == null) { Toast.makeText(context, "班级数据异常", Toast.LENGTH_SHORT).show(); return; } if (selectedClasscode.equals(checkClassUuid) && selectedClassPass.equals(checkPassword)) { Toast.makeText(context, "加入成功", Toast.LENGTH_LONG).show(); // 后续加入班级的逻辑写在这里 } else { Toast.makeText(context, "班级编码或密码错误", Toast.LENGTH_SHORT).show(); } // 结果日志放在回调内部打印 Log.d(TAG, "Retrieved Class UUID : " + checkClassUuid + " Retrieved Class Password : " + checkPassword); } @Override public void onCancelled(@NonNull DatabaseError error) { // 打印错误日志方便排查 Log.e(TAG, "查询失败: " + error.getMessage()); Toast.makeText(context, "查询失败:" + error.getMessage(), Toast.LENGTH_SHORT).show(); } }); });
内容的提问来源于stack exchange,提问作者Vinayak Sutar
相关产品推荐
相关产品推荐

