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

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方法
}

问题根源

  1. 全局变量冲突:urls和wholeList如果是全局变量,多次调用uploadFilesToStorage时会被不同分类的上传任务共享,导致不同分类的URL混加在一起。
  2. 频繁覆盖数据库:每上传一个文件就调用setValue(model),会覆盖之前的完整数据,且每次构建Model时传入的wholeList可能已混入其他分类的旧数据。
  3. 数据类型不匹配: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 05:34:55