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(); } }); } }
崩溃核心原因
- Firebase序列化失败:
Post和Post1类的构造函数没有初始化成员变量,也没有提供public的成员变量或getter方法。Firebase依赖反射读取类属性完成序列化,空构造逻辑会直接引发序列化异常,导致应用崩溃。 - 潜在空指针风险:从Intent获取的
docEmail、patname等核心参数如果未正确传递,会触发空指针异常。 - 异步操作未处理:
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
相关产品推荐
相关产品推荐

