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

Android Studio中用Firebase实时数据库push()存预约数据时应用崩溃求助

医院APP预约功能Firebase写入崩溃排查与修复

我正在开发一款医院APP的预约挂号功能,用户预约医生时需要把预约日期、患者邮箱、医生邮箱等信息同时存入Firebase实时数据库的Doctor Schedule和Patient Appointments两个节点。用push()方法实现时应用持续崩溃,相关代码如下:

public class Book extends AppCompatActivity {

    TextView selectedDate;
    Button calenderButton,ok;
    FirebaseAuth mAuth;
    DatabaseReference docUser, patRef;
    ProgressDialog loader;
    FirebaseDatabase database= FirebaseDatabase.getInstance();
    String Date;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_book);

        Intent intent = getIntent();

        String docEmail = intent.getStringExtra("message_key1");
        String patEmail = intent.getStringExtra("message_key2");
        String patname = intent.getStringExtra("message_key2.1");
        String docname = intent.getStringExtra("message_key2.2");
        String dphone = intent.getStringExtra("message_key2.3");

        selectedDate=findViewById(R.id.text);
        calenderButton=findViewById(R.id.calender);
        ok=findViewById(R.id.ok);

        loader = new ProgressDialog(this);
        mAuth = FirebaseAuth.getInstance();

        FirebaseUser user= mAuth.getInstance().getCurrentUser();

        MaterialDatePicker materialDatePicker=MaterialDatePicker.Builder.datePicker().
                setTitleText("Select date").setSelection(MaterialDatePicker.todayInUtcMilliseconds()).build();

        calenderButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                materialDatePicker.show(getSupportFragmentManager(),"Tag_Picker");
                materialDatePicker.addOnPositiveButtonClickListener(new MaterialPickerOnPositiveButtonClickListener() {
                    @Override
                    public void onPositiveButtonClick(Object selection) {
                        selectedDate.setText(materialDatePicker.getHeaderText());
                        Date=materialDatePicker.getHeaderText();
                    }
                });
            }
        });

          class Post {

              public Post(String Date, String Patient,String Email,String Doctor,String Status) {
                // ...
            }

        }

        class Post1 {

            public Post1(String Date, String Patient,String Doctor,String Email,String Phone,String Status) {
                // ...
            }

        }

        ok.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                if (Date != null) {

                    docUser = database.getReference().child("Doctor Schedule");
                    DatabaseReference newdocUser = docUser.push();

                    newdocUser.setValue(new Post(Date, patname,patEmail,docEmail,"Pending"));


                    patRef= database.getReference().child("Patient Appointments");
                    DatabaseReference newpatRef = patRef.push();

                    newpatRef.setValue(new Post1(Date,patEmail,docname,docEmail,dphone,"Pending"));

              
                }

                else {
                    Toast.makeText(Book.this, "Select date!", Toast.LENGTH_SHORT).show();

                }

                finish();

            }
        });
    }
}

崩溃核心原因

  1. Firebase序列化失败:Post和Post1类的构造函数没有初始化成员变量,也没有提供public的成员变量或getter方法。Firebase依赖反射读取类属性完成序列化,空构造逻辑会直接引发序列化异常,导致应用崩溃。
  2. 潜在空指针风险:从Intent获取的docEmail、patname等核心参数如果未正确传递,会触发空指针异常。
  3. 异步操作未处理:setValue()是异步方法,直接调用finish()可能在数据库写入完成前关闭页面,引发不可预期的错误。

修复步骤

1. 重构数据模型类

修改Post和Post1类,确保Firebase能正常序列化:

// 将这两个类移到onCreate方法外部,作为Book的内部类或单独的Java文件
class Post {
    public String date;
    public String patientName;
    public String patientEmail;
    public String doctorEmail;
    public String status;

    // Firebase反序列化需要空构造函数
    public Post() {}

    public Post(String date, String patientName, String patientEmail, String doctorEmail, String status) {
        this.date = date;
        this.patientName = patientName;
        this.patientEmail = patientEmail;
        this.doctorEmail = doctorEmail;
        this.status = status;
    }
}

class Post1 {
    public String date;
    public String patientEmail;
    public String doctorName;
    public String doctorEmail;
    public String doctorPhone;
    public String status;

    public Post1() {}

    public Post1(String date, String patientEmail, String doctorName, String doctorEmail, String doctorPhone, String status) {
        this.date = date;
        this.patientEmail = patientEmail;
        this.doctorName = doctorName;
        this.doctorEmail = doctorEmail;
        this.doctorPhone = doctorPhone;
        this.status = status;
    }
}

2. 添加参数校验与异步回调处理

在写入数据库前校验参数完整性,并通过回调监听写入结果:

ok.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (Date == null) {
            Toast.makeText(Book.this, "请选择日期!", Toast.LENGTH_SHORT).show();
            return;
        }
        // 校验核心参数是否为空
        if (TextUtils.isEmpty(patname) || TextUtils.isEmpty(patEmail) || 
            TextUtils.isEmpty(docEmail) || TextUtils.isEmpty(docname) || 
            TextUtils.isEmpty(dphone)) {
            Toast.makeText(Book.this, "缺少必要信息,请重试", Toast.LENGTH_SHORT).show();
            return;
        }

        loader.setMessage("正在提交预约...");
        loader.show();

        // 写入Doctor Schedule节点
        docUser = database.getReference().child("Doctor Schedule");
        DatabaseReference newdocUser = docUser.push();
        newdocUser.setValue(new Post(Date, patname, patEmail, docEmail, "Pending"))
                .addOnSuccessListener(new OnSuccessListener<Void>() {
                    @Override
                    public void onSuccess(Void unused) {
                        // 第一个节点写入成功后,写入Patient Appointments节点
                        patRef = database.getReference().child("Patient Appointments");
                        DatabaseReference newpatRef = patRef.push();
                        newpatRef.setValue(new Post1(Date, patEmail, docname, docEmail, dphone, "Pending"))
                                .addOnSuccessListener(new OnSuccessListener<Void>() {
                                    @Override
                                    public void onSuccess(Void unused) {
                                        loader.dismiss();
                                        Toast.makeText(Book.this, "预约提交成功", Toast.LENGTH_SHORT).show();
                                        finish();
                                    }
                                })
                                .addOnFailureListener(new OnFailureListener() {
                                    @Override
                                    public void onFailure(@NonNull Exception e) {
                                        loader.dismiss();
                                        Toast.makeText(Book.this, "预约失败:" + e.getMessage(), Toast.LENGTH_SHORT).show();
                                    }
                                });
                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        loader.dismiss();
                        Toast.makeText(Book.this, "预约失败:" + e.getMessage(), Toast.LENGTH_SHORT).show();
                    }
                });
    }
});

3. 可选:原子化批量写入

使用updateChildren()实现批量写入,确保两个节点的操作原子性(要么都成功,要么都失败):

ok.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (Date == null) {
            Toast.makeText(Book.this, "请选择日期!", Toast.LENGTH_SHORT).show();
            return;
        }
        if (TextUtils.isEmpty(patname) || TextUtils.isEmpty(patEmail) || 
            TextUtils.isEmpty(docEmail) || TextUtils.isEmpty(docname) || 
            TextUtils.isEmpty(dphone)) {
            Toast.makeText(Book.this, "缺少必要信息,请重试", Toast.LENGTH_SHORT).show();
            return;
        }

        loader.setMessage("正在提交预约...");
        loader.show();

        DatabaseReference rootRef = database.getReference();
        // 生成两个节点的唯一键
        String docScheduleKey = rootRef.child("Doctor Schedule").push().getKey();
        String patientApptKey = rootRef.child("Patient Appointments").push().getKey();

        Post post = new Post(Date, patname, patEmail, docEmail, "Pending");
        Post1 post1 = new Post1(Date, patEmail, docname, docEmail, dphone, "Pending");

        // 组装批量更新数据
        Map<String, Object> updates = new HashMap<>();
        updates.put("Doctor Schedule/" + docScheduleKey, post);
        updates.put("Patient Appointments/" + patientApptKey, post1);

        rootRef.updateChildren(updates)
                .addOnSuccessListener(new OnSuccessListener<Void>() {
                    @Override
                    public void onSuccess(Void unused) {
                        loader.dismiss();
                        Toast.makeText(Book.this, "预约提交成功", Toast.LENGTH_SHORT).show();
                        finish();
                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        loader.dismiss();
                        Toast.makeText(Book.this, "预约失败:" + e.getMessage(), Toast.LENGTH_SHORT).show();
                    }
                });
    }
});

内容的提问来源于stack exchange,提问作者New

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 05:15:27