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
相关产品推荐
相关产品推荐

