FirebaseAuth获取用户UID重复致预约数据被覆盖的问题修复
问题描述
我在Android Studio开发一款预约应用,功能是让用户通过Firebase实时数据库向固定医生列表提交预约。但FirebaseAuth.getInstance().getCurrentUser().getUid()始终返回同一个ID,导致新预约数据没有作为子节点添加,反而直接覆盖了原有子节点的信息。比如用户athy@gmail.com提交预约时,会覆盖已存在的nivi@gm.com的预约记录。我没有编写覆盖逻辑,推测是UID获取重复导致的问题,求修复方案。
现有代码
DoctorList.java
public class DoctorList extends AppCompatActivity { TextView doc1,doc2,doc3,doc4; FirebaseAuth mAuth; DatabaseReference patUser; ProgressDialog loader; FirebaseDatabase database= FirebaseDatabase.getInstance(); String Date; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_doctor_list); Intent intent = getIntent(); String email = intent.getStringExtra("message_key");//patient email doc1=findViewById(R.id.doc1); doc2=findViewById(R.id.doc2); doc3=findViewById(R.id.doc3); doc4=findViewById(R.id.doc4); loader = new ProgressDialog(this); mAuth = FirebaseAuth.getInstance(); FirebaseUser user= mAuth.getCurrentUser(); patUser= database.getReference().child("Patient Appointments"); doc1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { loader.setMessage("Please wait...."); loader.setCanceledOnTouchOutside(false); loader.show(); Intent intent= new Intent( DoctorList.this, Book.class); intent.putExtra("message_key1", "elise@doc.com"); intent.putExtra("message_key2", email); startActivity(intent); // 此处逻辑错误:此时还未从Book页面返回,Date会是null Intent intent1 = getIntent(); Date = intent1.getStringExtra("message"); String currentUserId = mAuth.getCurrentUser().getUid(); patUser= database.getReference().child("Patient Appointments").child(currentUserId); HashMap userInfo = new HashMap(); userInfo.put("Date",Date); userInfo.put("Patient",email); userInfo.put("Doctor","Dr.Elise Heather"); userInfo.put("Phone","5925866"); userInfo.put("Status","Pending"); patUser.updateChildren(userInfo).addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { if (task.isSuccessful()){ Toast.makeText(DoctorList.this, "Little more to go....", Toast.LENGTH_SHORT).show(); } else{ Toast.makeText(DoctorList.this, task.getException().toString(), Toast.LENGTH_SHORT).show(); } } }); loader.dismiss(); } }); } }
Book.java
public class Book extends AppCompatActivity { TextView selectedDate; Button calenderButton,ok; FirebaseAuth mAuth; DatabaseReference docUser; 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"); 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.getCurrentUser(); docUser= database.getReference().child("Doctor Schedule"); 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(); } }); } }); ok.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (Date != null) { String currentUserId = mAuth.getCurrentUser().getUid(); docUser = database.getReference().child("Doctor Schedule").child(currentUserId); HashMap userInfo = new HashMap(); userInfo.put("Date", Date); userInfo.put("Patient", patEmail); userInfo.put("Doctor", docEmail); userInfo.put("Status", "Pending"); docUser.updateChildren(userInfo).addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { if (task.isSuccessful()) { Toast.makeText(Book.this, "Appointment booked", Toast.LENGTH_SHORT).show(); Intent intent= new Intent( Book.this, DoctorList.class); intent.putExtra("message", Date); startActivity(intent); } else { Toast.makeText(Book.this, task.getException().toString(), Toast.LENGTH_SHORT).show(); } } }); } else { Toast.makeText(Book.this, "Select date!", Toast.LENGTH_SHORT).show(); } } }); } }
修复方案
问题根源分析
- DoctorList中数据写入时机错误:点击医生后立刻启动Book页面,紧接着尝试获取返回的
Date参数,此时Book页面还未返回,Date必然为null,且这部分写入逻辑完全多余——预约数据应该在Book页面选择日期后统一写入。 - 节点结构设计错误:直接用用户UID作为
Patient Appointments和Doctor Schedule的子节点键,导致同一用户多次预约会覆盖数据,不同用户若出现UID重复(比如测试时未切换账号)也会互相覆盖。 - FirebaseAuth实例化冗余:多次调用
mAuth.getInstance(),只需初始化一次即可。
具体修复步骤
1. 重构DoctorList.java,移除错误的写入逻辑
只保留跳转Book页面的逻辑,删除点击事件中所有数据库相关代码:
doc1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { loader.setMessage("Please wait...."); loader.setCanceledOnTouchOutside(false); loader.show(); Intent intent= new Intent( DoctorList.this, Book.class); intent.putExtra("message_key1", "elise@doc.com"); intent.putExtra("message_key2", email); startActivity(intent); loader.dismiss(); } });
2. 重构Book.java的数据库写入逻辑
- Patient Appointments:在用户UID下用
push()生成唯一子节点,存储每次预约,避免同一用户多次预约覆盖。 - Doctor Schedule:将医生邮箱作为父节点(需替换Firebase路径不允许的
@和.,比如elise@doc.com换成elise%40doc%2Ecom),再用push()生成唯一预约节点,方便按医生查询预约。 - 移除跳回DoctorList的逻辑(或改为跳转到预约成功页面),避免不必要的页面跳转。
修复后的Book.java点击事件代码:
ok.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (Date != null) { FirebaseUser currentUser = mAuth.getCurrentUser(); if (currentUser == null) { Toast.makeText(Book.this, "请先登录", Toast.LENGTH_SHORT).show(); return; } String currentUserId = currentUser.getUid(); // 处理医生邮箱,替换特殊字符适配Firebase路径 String formattedDocEmail = docEmail.replace("@", "%40").replace(".", "%2E"); // 写入用户预约记录:用户UID下生成唯一节点 DatabaseReference patAppRef = database.getReference("Patient Appointments") .child(currentUserId) .push(); // 生成唯一ID作为预约节点 HashMap<String, Object> patAppInfo = new HashMap<>(); patAppInfo.put("Date", Date); patAppInfo.put("Patient", patEmail); patAppInfo.put("Doctor", "Dr.Elise Heather"); patAppInfo.put("Phone", "5925866"); patAppInfo.put("Status", "Pending"); // 写入医生日程:医生邮箱节点下生成唯一预约节点 DatabaseReference docSchedRef = database.getReference("Doctor Schedule") .child(formattedDocEmail) .push(); HashMap<String, Object> docSchedInfo = new HashMap<>(); docSchedInfo.put("Date", Date); docSchedInfo.put("Patient", patEmail); docSchedInfo.put("Doctor", docEmail); docSchedInfo.put("Status", "Pending"); // 批量写入两个节点,保证原子性 HashMap<String, Object> batchUpdates = new HashMap<>(); batchUpdates.put(patAppRef.getPath().toString(), patAppInfo); batchUpdates.put(docSchedRef.getPath().toString(), docSchedInfo); database.getReference().updateChildren(batchUpdates).addOnCompleteListener(task -> { if (task.isSuccessful()) { Toast.makeText(Book.this, "预约成功", Toast.LENGTH_SHORT).show(); // 跳转到首页或预约列表页面,而非DoctorList finish(); // 关闭当前页面返回上一级 } else { Toast.makeText(Book.this, task.getException().toString(), Toast.LENGTH_SHORT).show(); } }); } else { Toast.makeText(Book.this, "请选择日期!", Toast.LENGTH_SHORT).show(); } } });
3. 验证用户登录状态
在使用mAuth.getCurrentUser()前,先判断用户是否已登录,避免NullPointerException:
FirebaseUser currentUser = mAuth.getCurrentUser(); if (currentUser == null) { // 处理未登录情况,比如跳转到登录页 Toast.makeText(this, "请先登录", Toast.LENGTH_SHORT).show(); startActivity(new Intent(this, LoginActivity.class)); finish(); return; }
最终效果
修复后:
- 每个用户的多次预约会作为
Patient Appointments/用户UID/唯一预约ID的子节点存在,不会覆盖。 - 医生的日程会按
Doctor Schedule/格式化医生邮箱/唯一预约ID存储,方便后续按医生查询所有预约。 - 数据写入逻辑统一在Book页面完成,避免时机错误导致的空值或重复写入。
内容的提问来源于stack exchange,提问作者New
相关产品推荐
相关产品推荐

