Android下Firebase实时数据库多分类URL上传重复问题求助
Firebase实时数据库分类URL重复问题排查与解决
问题场景
已实现Firebase存储的分类文件上传,但实时数据库中所有URL被重复添加到所有分类下。相关代码如下:
上传数据代码
private void uploadFilesToStorage(String userKey, List<Uri> list, String listName) { StorageReference mReference = sReference.child(mycertificate.getCert_num() + "/"); urls = new ArrayList<>(); wholeList = new LinkedHashMap<>(); for (Uri uri : list) { StorageReference sr = mReference.child(listName + "/" + System.currentTimeMillis() + "." + Tools.getFileExtn(BrowseFiles.this, uri)); sr.putFile(uri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { sr.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() { @Override public void onSuccess(Uri uri) { urls.add(uri.toString()); wholeList.put(listName,urls); Model model = new Model(userKey, mycertificate.getCert_num(), mycertificate.getCert_date(), mycertificate.getComp_name(), mycertificate.getComp_num(), mycertificate.getCountry(), mycertificate.getTrans(), mycertificate.isModel_13(), mycertificate.isChk_fact(), mycertificate.getOffers() , wholeList); uploadDataToRTDB(model); } }); } }); } } private void uploadDataToRTDB(Model model) { DatabaseReference reference = FirebaseDatabase.getInstance() .getReference("Database"); reference.child("myfiles") .child(modal.getCert_num).setValue(model); }
主Activity调用代码
for (int i = 0; i < mylists.size(); i++) { uploadFilesToStorage(UUID, mylists.get(i), fragmentsIndx.get((i + 1))); }
mylists为List<List<Uri>>,包含所有待上传的Uri列表。
Model类代码
package com.mkandeel.kodsadmin.models; import java.util.List; import java.util.Map; public class Model { private String cert_num; private String cert_date; private String comp_name; private String comp_num; private String country; private String trans; private boolean model_13; private boolean isFact; private String offers; private List<List<String>> lists; private String userKey; public Model(){} public Model(String userKey,String cert_num, String cert_date, String comp_name, String comp_num, String country, String trans, boolean model_13, boolean isFact, String offers, List<List<String>> lists) { this.cert_num = cert_num; this.cert_date = cert_date; this.comp_name = comp_name; this.comp_num = comp_num; this.country = country; this.trans = trans; this.model_13 = model_13; this.isFact = isFact; this.offers = offers; this.lists = lists; this.userKey = userKey; } // 原代码中包含的getter、setter方法 }
问题根源
- 全局变量冲突:
urls和wholeList如果是全局变量,多次调用uploadFilesToStorage时会被不同分类的上传任务共享,导致不同分类的URL混加在一起。 - 频繁覆盖数据库:每上传一个文件就调用
setValue(model),会覆盖之前的完整数据,且每次构建Model时传入的wholeList可能已混入其他分类的旧数据。 - 数据类型不匹配:Model构造函数接收的是
List<List<String>>类型,但代码中传入的是LinkedHashMap<String, List<String>>,类型不兼容会导致序列化异常,最终造成数据结构混乱。
修复方案
1. 修正Model类数据结构
将lists字段改为Map<String, List<String>>,匹配实际要存储的分类-URL列表结构:
package com.mkandeel.kodsadmin.models; import java.util.List; import java.util.Map; public class Model { private String cert_num; private String cert_date; private String comp_name; private String comp_num; private String country; private String trans; private boolean model_13; private boolean isFact; private String offers; private Map<String, List<String>> lists; // 改为Map类型 private String userKey; public Model(){} // 构造函数同步调整参数类型 public Model(String userKey,String cert_num, String cert_date, String comp_name, String comp_num, String country, String trans, boolean model_13, boolean isFact, String offers, Map<String, List<String>> lists) { this.userKey = userKey; this.cert_num = cert_num; this.cert_date = cert_date; this.comp_name = comp_name; this.comp_num = comp_num; this.country = country; this.trans = trans; this.model_13 = model_13; this.isFact = isFact; this.offers = offers; this.lists = lists; } // 对应的getter和setter public Map<String, List<String>> getLists() { return lists; } public void setLists(Map<String, List<String>> lists) { this.lists = lists; } // 其他getter、setter保持不变 }
2. 重构上传逻辑,避免全局变量冲突
把urls改为当前分类的局部变量,且仅在当前分类所有文件上传完成后,再合并到数据库:
private void uploadFilesToStorage(String userKey, List<Uri> list, String listName) { StorageReference mReference = sReference.child(mycertificate.getCert_num() + "/"); List<String> categoryUrls = new ArrayList<>(); // 当前分类专属的URL列表 int totalFiles = list.size(); AtomicInteger uploadedCount = new AtomicInteger(0); for (Uri uri : list) { StorageReference sr = mReference.child(listName + "/" + System.currentTimeMillis() + "." + Tools.getFileExtn(BrowseFiles.this, uri)); sr.putFile(uri).addOnSuccessListener(taskSnapshot -> { sr.getDownloadUrl().addOnSuccessListener(downloadUri -> { categoryUrls.add(downloadUri.toString()); uploadedCount.incrementAndGet(); // 当前分类所有文件上传完成后,更新数据库 if (uploadedCount.get() == totalFiles) { mergeCategoryToDatabase(userKey, listName, categoryUrls); } }); }).addOnFailureListener(e -> { // 上传失败也计数,避免阻塞后续流程 uploadedCount.incrementAndGet(); }); } } // 合并分类数据到数据库,避免覆盖原有分类 private void mergeCategoryToDatabase(String userKey, String listName, List<String> categoryUrls) { DatabaseReference dbRef = FirebaseDatabase.getInstance() .getReference("Database") .child("myfiles") .child(mycertificate.getCert_num()); // 先读取现有数据,再合并新分类 dbRef.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { Model existingModel = snapshot.getValue(Model.class); Map<String, List<String>> categoryMap; if (existingModel == null) { // 首次上传,创建新Model categoryMap = new LinkedHashMap<>(); categoryMap.put(listName, categoryUrls); Model newModel = new Model(userKey, mycertificate.getCert_num(), mycertificate.getCert_date(), mycertificate.getComp_name(), mycertificate.getComp_num(), mycertificate.getCountry(), mycertificate.getTrans(), mycertificate.isModel_13(), mycertificate.isChk_fact(), mycertificate.getOffers(), categoryMap); dbRef.setValue(newModel); } else { // 合并现有分类与新分类 categoryMap = existingModel.getLists(); if (categoryMap == null) categoryMap = new LinkedHashMap<>(); categoryMap.put(listName, categoryUrls); existingModel.setLists(categoryMap); dbRef.setValue(existingModel); } } @Override public void onCancelled(@NonNull DatabaseError error) { // 处理数据库读取失败逻辑 } }); }
3. 主调用逻辑保持不变
原主Activity的循环调用无需修改,现在每个分类的上传任务独立维护自己的URL列表,且仅在该分类所有文件上传完成后才更新数据库,彻底避免了数据混加和覆盖问题。
内容的提问来源于stack exchange,提问作者Mohamed Hossam
相关产品推荐
相关产品推荐

