Firebase Storage链接未写入实时数据库问题排查
问题根源:异步操作的执行顺序搞反了
哥们,你这问题典型的异步操作时序错误——Firebase Storage的文件上传、下载链接获取都是后台异步执行的,但你的代码在这些异步任务还没完成(还没把真实链接赋值给uploadData)的时候,就已经把uploadData写入实时数据库了。
咱们捋下你代码的实际执行流程:
- 点击按钮,启动图片和文档的异步上传任务(这俩任务在后台跑,不会阻塞主线程)
- 立刻关闭进度框,给
uploadData设置name和info - 直接把
uploadData写入数据库(这时候imgURL和docURL还是默认的空值/Null,因为异步任务还没跑完) - 过了一会儿,异步任务完成,才把真实链接赋值给
uploadData,但这时候数据库已经写完了,自然看不到链接
解决方案:等所有异步任务完成后再写数据库
核心思路是:必须确保图片和文档的下载链接都已经拿到(或者确认上传失败),再执行数据库写入操作。这里给你两种实现方式,选顺手的用就行。
方式一:用计数跟踪任务完成状态(易理解)
updata.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { progressDialog.setTitle("Uploading Files"); progressDialog.show(); final UploadData uploadData = new UploadData(); String info = infoText.getText().toString(); String event = eventName.getText().toString(); uploadData.setName(event); uploadData.setInfo(info); // 统计需要执行的上传任务数 int totalTasks = 0; if (ImgPathUri != null) totalTasks++; if (DocPathUri != null) totalTasks++; // 用来记录已完成的任务数 int completedTasks = 0; // 如果没有文件要上传,直接写数据库 if (totalTasks == 0) { writeToDatabase(event, uploadData); progressDialog.dismiss(); return; } // 上传图片逻辑 if (ImgPathUri != null) { StorageReference imgRef = storageReference.child(StoragePath + System.currentTimeMillis() + "." + getExtension(ImgPathUri)); imgRef.putFile(ImgPathUri) .addOnSuccessListener(taskSnapshot -> { taskSnapshot.getStorage().getDownloadUrl() .addOnSuccessListener(uri -> { uploadData.setImgURL(uri.toString()); completedTasks++; checkAndWrite(completedTasks, totalTasks, event, uploadData); }) .addOnFailureListener(e -> { Toast.makeText(addEventActivity.this, "图片链接获取失败", Toast.LENGTH_SHORT).show(); completedTasks++; checkAndWrite(completedTasks, totalTasks, event, uploadData); }); }) .addOnFailureListener(e -> { Toast.makeText(addEventActivity.this, "图片上传失败", Toast.LENGTH_SHORT).show(); completedTasks++; checkAndWrite(completedTasks, totalTasks, event, uploadData); }); } // 上传文档逻辑 if (DocPathUri != null) { StorageReference docRef = storageReference.child(StoragePath + System.currentTimeMillis() + "." + getExtension(DocPathUri)); docRef.putFile(DocPathUri) .addOnSuccessListener(taskSnapshot -> { taskSnapshot.getStorage().getDownloadUrl() .addOnSuccessListener(uri -> { uploadData.setDocURL(uri.toString()); completedTasks++; checkAndWrite(completedTasks, totalTasks, event, uploadData); }) .addOnFailureListener(e -> { Log.e("TAG", "文档链接获取失败", e); completedTasks++; checkAndWrite(completedTasks, totalTasks, event, uploadData); }); }) .addOnFailureListener(e -> { Toast.makeText(addEventActivity.this, "文档上传失败", Toast.LENGTH_SHORT).show(); completedTasks++; checkAndWrite(completedTasks, totalTasks, event, uploadData); }); } } // 检查所有任务是否完成,完成则写入数据库 private void checkAndWrite(int completed, int total, String event, UploadData data) { if (completed == total) { progressDialog.dismiss(); writeToDatabase(event, data); Toast.makeText(addEventActivity.this, "数据已保存", Toast.LENGTH_SHORT).show(); } } // 封装数据库写入逻辑 private void writeToDatabase(String event, UploadData data) { databaseReference.child(event).setValue(data); } });
方式二:用Firebase Tasks组合异步任务(更简洁)
如果你的Firebase SDK版本≥16.0.0,可以用Tasks.whenAllSuccess()来组合多个异步任务,代码更清爽:
updata.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { progressDialog.setTitle("Uploading Files"); progressDialog.show(); final UploadData uploadData = new UploadData(); String info = infoText.getText().toString(); String event = eventName.getText().toString(); uploadData.setName(event); uploadData.setInfo(info); // 把上传逻辑封装成返回Task<String>的方法 Task<String> imgTask = ImgPathUri != null ? uploadFile(ImgPathUri) : Tasks.forResult(null); Task<String> docTask = DocPathUri != null ? uploadFile(DocPathUri) : Tasks.forResult(null); // 等待两个任务都完成 Tasks.whenAllSuccess(imgTask, docTask) .addOnSuccessListener(results -> { progressDialog.dismiss(); String imgLink = (String) results.get(0); String docLink = (String) results.get(1); if (imgLink != null) uploadData.setImgURL(imgLink); if (docLink != null) uploadData.setDocURL(docLink); databaseReference.child(event).setValue(uploadData); Toast.makeText(addEventActivity.this, "数据已保存", Toast.LENGTH_SHORT).show(); }) .addOnFailureListener(e -> { progressDialog.dismiss(); Toast.makeText(addEventActivity.this, "上传失败", Toast.LENGTH_SHORT).show(); }); } // 通用上传方法,返回获取下载链接的Task private Task<String> uploadFile(Uri fileUri) { StorageReference fileRef = storageReference.child(StoragePath + System.currentTimeMillis() + "." + getExtension(fileUri)); return fileRef.putFile(fileUri) .continueWithTask(task -> fileRef.getDownloadUrl()) .continueWithTask(task -> Tasks.forResult(task.getResult().toString())); } });
内容的提问来源于stack exchange,提问作者luc
相关产品推荐
相关产品推荐

