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

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();
                }
            }
        });
    }
}
修复方案

问题根源分析

  1. DoctorList中数据写入时机错误:点击医生后立刻启动Book页面,紧接着尝试获取返回的Date参数,此时Book页面还未返回,Date必然为null,且这部分写入逻辑完全多余——预约数据应该在Book页面选择日期后统一写入。
  2. 节点结构设计错误:直接用用户UID作为Patient Appointments和Doctor Schedule的子节点键,导致同一用户多次预约会覆盖数据,不同用户若出现UID重复(比如测试时未切换账号)也会互相覆盖。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 08:16:02