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

Android Studio中无法加载Firebase实时数据库所有数据到RecyclerView

解决Firebase实时数据库多用户广告数据加载问题

问题说明

在Android Studio中使用Firebase实时数据库时,Advertisements节点下按用户ID分文件夹存储广告数据,但现有LoadAdvertisements方法只能加载指定用户ID文件夹下的广告,无法展示所有用户的广告内容,RecyclerView本身功能正常。

数据库结构

{
  "Advertisements": {
    "Fg65Rt43Fhjn5js6hGJ": [
      {
        "advertisement_price": "50e",
        "description": "propale skije",
        "thumbnailURL": "https://firebasestorage.googleapis.com/v0/b/skisell-c295d.appspot.com/o/PostImages%2FZxw5nuwqXRfWJmlN93i9xBVq2ml1%2F0%2Fthumbnail?alt=media&token=19f41472-cb3e-49fb-8100",
        "title": "cao"
      },
      {
        "advertisement_price": "40e",
        "description": "nesto",
        "thumbnailURL": "https://firebasestorage.googleapis.com/v0/b/skisell-c295d.appspot.com/o/PostImages%2FZxw5nuwqXRfWJmlN93i9xBVq2ml1%2F0%2Fthumbnail?alt=media&token=19f41472-cb3e-49fb-8100",
        "title": "isto nesto"
      }
    ],
    "Xd45GhtR569Ds12Xdfiu6": [
      {
        "advertisement_price": "150e",
        "description": "blah",
        "thumbnailURL": "https://firebasestorage.googleapis.com/v0/b/skisell-c295d.appspot.com/o/PostImages%2FZxw5nuwqXRfWJmlN93i9xBVq2ml1%2F0%2Fthumbnail?alt=media&token=19f41472-cb3e-49fb-8100",
        "title": "nesto"
      }
    ],
    "Zxw5nuwqXRfWJmlN93i9xBVq2ml1": [
      {
        "advertisement_price": "100e",
        "description": "elan",
        "thumbnailURL": "https://firebasestorage.googleapis.com/v0/b/skisell-c295d.appspot.com/o/PostImages%2FZxw5nuwqXRfWJmlN93i9xBVq2ml1%2F0%2Fthumbnail?alt=media&token=19f41472-cb3e-49fb-8100",
        "title": "skije"
      }
    ]
  },
  "Users": {
    "Zxw5nuwqXRfWJmlN93i9xBVq2ml1": {
      "city": "Kraljevo",
      "name": "Milutin",
      "profileImage": "https://firebasestorage.googleapis.com/v0/b/skisell-c295d.appspot.com/o/ProfileImages%2FZxw5nuwqXRfWJmlN93i9xBVq2ml1?alt=media&token=761b55d9-1470",
      "status": "offline",
      "surname": "Nedeljkovic",
      "username": "micocomi"
    }
  }
}

当前代码

//this is the declaration in the OnCreate method
//DatabaseReference AdvertisementsRef;
//AdvertisementsRef = FirebaseDatabase.getInstance().getReference().child("Advertisements");

private void LoadAdvertisements() {
    ValueEventListener eventListener = new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {
                options = new FirebaseRecyclerOptions.Builder<Advertisements>().setQuery(AdvertisementsRef.child("Fg65Rt43Fhjn5js6hGJ"), Advertisements.class).build();
                adapter = new FirebaseRecyclerAdapter<Advertisements, MyViewHolder>(options) {
                    @Override
                    protected void onBindViewHolder(@NonNull MyViewHolder holder, int position, @NonNull Advertisements model) {
                        holder.AdTitle.setText(model.getTitle());
                        holder.AdPrice.setText(model.getAdvertisement_price());
                        Picasso.get().load(model.getThumbnailURL()).into(holder.thumbnail1);
                    }

                    @NonNull
                    @Override
                    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
                        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_design, parent, false);
                        return new MyViewHolder(view);
                    }
                };
                adapter.startListening();
                recyclerView.setAdapter(adapter);
        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {
            Toast.makeText(MainActivity.this, "Oops, something went wrong", Toast.LENGTH_SHORT).show();
        }
    };
    AdvertisementsRef.addListenerForSingleValueEvent(eventListener);
}

解决方案

方案一:遍历现有节点收集所有广告数据(无需修改数据库结构)

现有代码的问题是直接指定了单个用户ID节点,需要遍历所有用户ID节点,将每个节点下的广告数据收集到统一列表中,再用普通RecyclerView Adapter展示:

  1. 定义全局的广告列表和普通Adapter:
private List<Advertisements> allAdvertisements = new ArrayList<>();
private AdvertisementAdapter advertisementAdapter;
  1. 在onCreate方法中初始化Adapter并绑定到RecyclerView:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    // 初始化RecyclerView(假设已完成布局绑定)
    recyclerView = findViewById(R.id.recycler_view);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    
    // 初始化Adapter
    advertisementAdapter = new AdvertisementAdapter(allAdvertisements);
    recyclerView.setAdapter(advertisementAdapter);
    
    // 初始化数据库引用
    AdvertisementsRef = FirebaseDatabase.getInstance().getReference().child("Advertisements");
    
    // 加载广告
    LoadAdvertisements();
}
  1. 修改LoadAdvertisements方法遍历所有节点:
private void LoadAdvertisements() {
    ValueEventListener eventListener = new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {
            allAdvertisements.clear(); // 清空旧数据避免重复
            // 遍历每个用户ID节点
            for (DataSnapshot userSnapshot : snapshot.getChildren()) {
                // 遍历该用户下的所有广告
                for (DataSnapshot adSnapshot : userSnapshot.getChildren()) {
                    Advertisements ad = adSnapshot.getValue(Advertisements.class);
                    if (ad != null) {
                        allAdvertisements.add(ad);
                    }
                }
            }
            advertisementAdapter.notifyDataSetChanged(); // 更新RecyclerView
        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {
            Toast.makeText(MainActivity.this, "Oops, something went wrong", Toast.LENGTH_SHORT).show();
        }
    };
    // 用addValueEventListener可实时监听数据变化,若只需加载一次可保留addListenerForSingleValueEvent
    AdvertisementsRef.addValueEventListener(eventListener);
}
  1. 实现普通的RecyclerView Adapter:
class AdvertisementAdapter extends RecyclerView.Adapter<MyViewHolder> {
    private List<Advertisements> adList;

    public AdvertisementAdapter(List<Advertisements> adList) {
        this.adList = adList;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_design, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        Advertisements model = adList.get(position);
        holder.AdTitle.setText(model.getTitle());
        holder.AdPrice.setText(model.getAdvertisement_price());
        Picasso.get().load(model.getThumbnailURL()).into(holder.thumbnail1);
    }

    @Override
    public int getItemCount() {
        return adList.size();
    }
}

方案二:调整数据库结构(推荐,更符合Firebase最佳实践)

Firebase实时数据库中不推荐使用数组存储列表数据(并发修改易冲突、查询灵活性差),建议将广告直接存储在Advertisements节点下,用push()生成的唯一键标识每个广告,并添加userId字段关联用户:

调整后的数据库结构

{
  "Advertisements": {
    "-NxYzaKdF789abc": {
      "userId": "Fg65Rt43Fhjn5js6hGJ",
      "advertisement_price": "50e",
      "description": "propale skije",
      "thumbnailURL": "https://firebasestorage.googleapis.com/v0/b/skisell-c295d.appspot.com/o/PostImages%2FZxw5nuwqXRfWJmlN93i9xBVq2ml1%2F0%2Fthumbnail?alt=media&token=19f41472-cb3e-49fb-8100",
      "title": "cao"
    },
    "-NxYzbLmN123def": {
      "userId": "Fg65Rt43Fhjn5js6hGJ",
      "advertisement_price": "40e",
      "description": "nesto",
      "thumbnailURL": "https://firebasestorage.googleapis.com/v0/b/skisell-c295d.appspot.com/o/PostImages%2FZxw5nuwqXRfWJmlN93i9xBVq2ml1%2F0%2Fthumbnail?alt=media&token=19f41472-cb3e-49fb-8100",
      "title": "isto nesto"
    },
    "-NxYzcOpQ456ghi": {
      "userId": "Xd45GhtR569Ds12Xdfiu6",
      "advertisement_price": "150e",
      "description": "blah",
      "thumbnailURL": "https://firebasestorage.googleapis.com/v0/b/skisell-c295d.appspot.com/o/PostImages%2FZxw5nuwqXRfWJmlN93i9xBVq2ml1%2F0%2Fthumbnail?alt=media&token=19f41472-cb3e-49fb-8100",
      "title": "nesto"
    }
  }
}

简化后的加载代码

此时可以直接用FirebaseRecyclerAdapter查询所有广告:

private void LoadAdvertisements() {
    FirebaseRecyclerOptions<Advertisements> options =
            new FirebaseRecyclerOptions.Builder<Advertisements>()
                    .setQuery(AdvertisementsRef, Advertisements.class)
                    .build();

    FirebaseRecyclerAdapter<Advertisements, MyViewHolder> adapter =
            new FirebaseRecyclerAdapter<Advertisements, MyViewHolder>(options) {
                @Override
                protected void onBindViewHolder(@NonNull MyViewHolder holder, int position, @NonNull Advertisements model) {
                    holder.AdTitle.setText(model.getTitle());
                    holder.AdPrice.setText(model.getAdvertisement_price());
                    Picasso.get().load(model.getThumbnailURL()).into(holder.thumbnail1);
                }

                @NonNull
                @Override
                public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
                    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_design, parent, false);
                    return new MyViewHolder(view);
                }
            };

    recyclerView.setAdapter(adapter);
    adapter.startListening();
}

内容的提问来源于stack exchange,提问作者Milutin Nedeljkovic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 15:32:02