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

为什么从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
问题原因
  1. 变量selectedClasscode未完成赋值:点击事件逻辑中仅对selectedClassPass做了取值赋值,没有对班级编码变量selectedClasscode赋值,导致后续校验逻辑中该变量为null,匹配失败。
  2. 异步操作特性导致外部取值为空:Firebase Realtime Database的查询是异步操作,addValueEventListener的回调方法onDataChange执行时机晚于外部的同步日志打印代码,所以在回调外部打印checkClassUuid和checkPassword时,回调还未执行,变量自然为null。
  3. 缺少错误捕获逻辑:onCancelled方法为空,当出现权限不足、网络异常、节点不存在等问题时无法排查具体错误。
修复方案
  1. 补充selectedClasscode赋值逻辑,在点击事件中获取班级密码的代码后增加一行:
selectedClasscode = classCode.getEditableText().toString().trim();
  1. 所有需要使用查询返回结果的逻辑全部放在onDataChange回调内部执行,不要在回调外部访问异步返回的变量。
  2. 增加空校验和错误日志逻辑,避免空指针异常,同时完善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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 05:27:00