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

Android中如何从两个Firebase表获取数据到RecyclerView

解决Firebase双数据源(Food+User)在RecyclerView展示的问题

看来你已经搞定了Food表数据加载和RecyclerView的基础搭建,现在就差把User表的用户名关联进来展示了对吧?我一步步帮你捋清楚怎么做:

第一步:确保数据关联的基础结构

首先你的Firebase数据库得有正确的关联字段,Food表每个条目里必须存对应的用户ID,用来关联User表的用户。比如数据库结构大概是这样:

- Food
  - foodId_1
    - name: "番茄炒蛋"
    - status: "AVAILABLE"
    - userId: "user_123"  // 核心关联字段,必须有
    - ...其他食品属性
- User
  - user_123
    - username: "张三"
    - ...其他用户属性

同时你的Food实体类要补上userId字段,记得加getter/setter,还要在toMap()方法里包含这个字段:

public class Food {
    public String key;
    public String name;
    public String status;
    public String userId; // 新增关联字段
    
    public Food() {} // Firebase需要空构造函数

    // 带参构造、getter/setter自行补充

    public Map<String, Object> toMap() {
        HashMap<String, Object> result = new HashMap<>();
        result.put("name", name);
        result.put("status", status);
        result.put("userId", userId); // 加入关联字段
        // 其他字段...
        return result;
    }
}

第二步:创建组合类存储食品+用户信息

因为要同时展示食品详情和用户名,最好搞个组合类来封装这俩数据,避免在Adapter里做异步查询:

public class FoodWithUser {
    private Food food;
    private String username;

    public FoodWithUser(Food food, String username) {
        this.food = food;
        this.username = username;
    }

    public Food getFood() { return food; }
    public String getUsername() { return username; }
}

第三步:修改HomeFragment加载双数据源

把Fragment里的集合和Adapter类型改成List<FoodWithUser>,然后在获取Food数据后,根据userId去User表查用户名:

先改Fragment里的变量:

private List<FoodWithUser> result; // 替换原来的List<Food>
private foodadapter adapter;

然后修改onCreateView里的初始化:

result = new ArrayList<>();
adapter = new foodadapter(result);
recyclerView.setAdapter(adapter);

接下来重写updateList()方法,处理双数据源的加载:

private void updateList() {
    DatabaseReference userRef = database.getReference("User"); // 获取User表引用
    // 缓存用户信息,避免重复查询(优化用)
    Map<String, String> userCache = new HashMap<>();

    ref.orderByChild("status").equalTo("AVAILABLE").addChildEventListener(new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s) {
            Food food = dataSnapshot.getValue(Food.class);
            food.key = dataSnapshot.getKey(); // 别忘了设置Food的key

            // 先查缓存,没有再去Firebase查
            if (userCache.containsKey(food.userId)) {
                String username = userCache.get(food.userId);
                result.add(new FoodWithUser(food, username));
                adapter.notifyDataSetChanged();
            } else {
                userRef.child(food.userId).addListenerForSingleValueEvent(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot userSnapshot) {
                        String username = userSnapshot.exists() 
                            ? userSnapshot.child("username").getValue(String.class) 
                            : "匿名用户";
                        userCache.put(food.userId, username); // 存入缓存
                        result.add(new FoodWithUser(food, username));
                        adapter.notifyDataSetChanged();
                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {
                        Toast.makeText(getContext(), "加载用户信息失败", Toast.LENGTH_SHORT).show();
                    }
                });
            }
        }

        @Override
        public void onChildChanged(DataSnapshot dataSnapshot, String s) {
            Food updatedFood = dataSnapshot.getValue(Food.class);
            updatedFood.key = dataSnapshot.getKey();

            // 找到对应的条目更新
            for (int i = 0; i < result.size(); i++) {
                FoodWithUser fwu = result.get(i);
                if (fwu.getFood().key.equals(updatedFood.key)) {
                    if (userCache.containsKey(updatedFood.userId)) {
                        result.set(i, new FoodWithUser(updatedFood, userCache.get(updatedFood.userId)));
                        adapter.notifyItemChanged(i);
                    } else {
                        userRef.child(updatedFood.userId).addListenerForSingleValueEvent(new ValueEventListener() {
                            @Override
                            public void onDataChange(DataSnapshot userSnapshot) {
                                String username = userSnapshot.exists() 
                                    ? userSnapshot.child("username").getValue(String.class) 
                                    : "匿名用户";
                                userCache.put(updatedFood.userId, username);
                                result.set(i, new FoodWithUser(updatedFood, username));
                                adapter.notifyItemChanged(i);
                            }

                            @Override
                            public void onCancelled(DatabaseError databaseError) {}
                        });
                    }
                    break;
                }
            }
        }

        @Override
        public void onChildRemoved(DataSnapshot dataSnapshot) {
            Food removedFood = dataSnapshot.getValue(Food.class);
            removedFood.key = dataSnapshot.getKey();
            // 找到对应的条目移除
            for (int i = 0; i < result.size(); i++) {
                if (result.get(i).getFood().key.equals(removedFood.key)) {
                    result.remove(i);
                    adapter.notifyItemRemoved(i);
                    break;
                }
            }
        }

        @Override
        public void onChildMoved(DataSnapshot dataSnapshot, String s) {}
        @Override
        public void onCancelled(DatabaseError databaseError) {}
    });
}

第四步:补全并修改foodadapter

把Adapter改成适配FoodWithUser,补全没写完的代码:

package com.example.user8.myapplication;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.List;

public class foodadapter extends RecyclerView.Adapter<foodadapter.foodviewholder> {
    private List<FoodWithUser> list;
    private Context context;

    public foodadapter(List<FoodWithUser> list) {
        this.list = list;
    }

    @Override
    public foodviewholder onCreateViewHolder(ViewGroup parent, int viewType) {
        context = parent.getContext();
        // 替换成你的item布局文件名
        View v = LayoutInflater.from(context).inflate(R.layout.item_food, parent, false);
        return new foodviewholder(v);
    }

    @Override
    public void onBindViewHolder(foodviewholder holder, int position) {
        FoodWithUser fwu = list.get(position);
        Food food = fwu.getFood();
        
        // 设置食品信息
        holder.tvFoodName.setText(food.name);
        holder.tvFoodStatus.setText(food.status);
        // 设置用户名
        holder.tvUsername.setText(fwu.getUsername());
    }

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

    public class foodviewholder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener {
        TextView tvFoodName, tvFoodStatus, tvUsername;

        public foodviewholder(View itemView) {
            super(itemView);
            // 替换成你布局里对应的ID
            tvFoodName = itemView.findViewById(R.id.tv_food_name);
            tvFoodStatus = itemView.findViewById(R.id.tv_food_status);
            tvUsername = itemView.findViewById(R.id.tv_username);
            itemView.setOnCreateContextMenuListener(this);
        }

        @Override
        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
            menu.add(0, 0, getAdapterPosition(), "删除");
            menu.add(0, 1, getAdapterPosition(), "修改");
        }
    }
}

最后检查你的Item布局

确保item_food.xml里有显示用户名的TextView,比如:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/tv_food_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textStyle="bold"/>

    <TextView
        android:id="@+id/tv_food_status"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="14sp"
        android:textColor="#666"/>

    <TextView
        android:id="@+id/tv_username"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="14sp"
        android:textColor="#009688"
        android:layout_marginTop="4dp"/>

</LinearLayout>

这样一套操作下来,你的RecyclerView就能同时展示食品详情和对应的用户名啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:35:59