Firebase数据库未按Model类存储用户信息问题排查求助
问题背景
开发了一个上传PDF到Firebase的Fragment,期望在resume-uploads节点存储文件名、文件URL、上传用户名及用户学号,但目前该节点仅存储文件名和URL,用户名与学号未被正确写入。
错误原因分析
1. 异步数据读取导致赋值延迟
在uploadPDFFile方法中,调用setUsernameAndEnrollment()后立刻创建UploadResumeFile对象并写入数据库,但addValueEventListener是异步操作——此时username和enrollment还未从数据库获取到实际值,依然为null,因此无法被写入节点。
2. 模型类Getter方法命名不符合Firebase序列化规则
UploadResumeFile类中,username字段对应的Getter方法是getUser_name(),Firebase序列化时会根据Getter方法名生成字段名(即user_name),但你期望存储的字段是username,两者不匹配,导致即使有值也无法正确映射到目标字段。
修复方案
方案一:修正异步数据读取逻辑
将创建UploadResumeFile并写入数据库的逻辑,放到数据库读取回调的onDataChange方法中,确保获取到用户数据后再执行写入操作;同时使用addListenerForSingleValueEvent替代addValueEventListener,因为只需要获取一次用户数据,避免不必要的持续监听。
方案二:修正模型类Getter/Setter方法命名
将UploadResumeFile中username字段的Getter方法改为getUsername(),Setter方法改为setUsername(),保证与字段名一致,符合Firebase的序列化规则。
代码修改示例
1. 修改uploadPDFFile方法的异步逻辑
private void uploadPDFFile(Uri data) { final ProgressDialog progressDialog = new ProgressDialog(getActivity()); progressDialog.setTitle("uploading..."); progressDialog.show(); StorageReference reference = storageReference.child("resumeUploads/" + System.currentTimeMillis() + ".pdf"); reference.putFile(data).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { Task<Uri> uriTask = taskSnapshot.getStorage().getDownloadUrl(); while (!uriTask.isComplete()) ; Uri url = uriTask.getResult(); // 直接在回调中获取用户数据,确保异步完成后再写入数据库 ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { UserDataStore userDataStore = snapshot.getValue(UserDataStore.class); if (user != null && userDataStore != null) { String username = userDataStore.getName(); String enrollment = userDataStore.getEnrollment(); // 创建上传对象并写入数据库 UploadResumeFile uploadResumeFile = new UploadResumeFile( editPDFName.getText().toString(), url.toString(), username, enrollment ); if (FirebaseAuth.getInstance().getCurrentUser() != null) { databaseReference.child(databaseReference.push().getKey()).setValue(uploadResumeFile); } Toast.makeText(getActivity(), "File Uploaded Successfully", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(getActivity(), "Failed to retrieve user data", Toast.LENGTH_SHORT).show(); } progressDialog.dismiss(); } @Override public void onCancelled(@NonNull DatabaseError error) { Toast.makeText(getActivity(), "Database error: " + error.getMessage(), Toast.LENGTH_SHORT).show(); progressDialog.dismiss(); } }); } }).addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() { @Override public void onProgress(@NonNull UploadTask.TaskSnapshot snapshot) { progressDialog.setMessage("Uploading..."); } }); }
2. 修正UploadResumeFile模型类的方法命名
public class UploadResumeFile { public String name; public String url; public String username; public String enrollment; public UploadResumeFile() {} public UploadResumeFile(String name, String url, String username, String enrollment) { this.name = name; this.url = url; this.username = username; this.enrollment = enrollment; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } // 修正Getter/Setter方法名,与字段名保持一致 public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getEnrollment() { return enrollment; } public void setEnrollment(String enrollment) { this.enrollment = enrollment; } }
额外优化建议
- 移除原有的
setUsernameAndEnrollment()方法,避免冗余逻辑。 - 增加数据库读取失败的错误提示,提升用户体验。
- 可考虑在登录时将用户数据缓存到本地,避免每次上传都重复读取数据库,提升操作效率。
内容的提问来源于stack exchange,提问作者Anushka yadav

