Firebase获取指定子节点Keys到ArrayList出错,仅返回Ingridients,求解决
Firebase Database无法获取目标节点Keys的问题排查与解决
需求背景
我需要先将IngridientIdOne下的所有keys存入ArrayList,再将IngridientIdTwo下的所有keys存入ArrayList。
数据库结构
{ "Receptes" : { "Ingridients" : { "IngridientIdOne" : { "Carrot" : true, "Salt" : true, "Apples" : true }, "IngridientIdTwo" : { "Strawberries" : true, "Sugar" : true, "Bananas" : true } } } }
尝试的代码
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference(); DatabaseReference ingridientsRef = rootRef.child("Receptes").child("Ingridients"); ValueEventListener valueEventListener = new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { for(DataSnapshot ds : dataSnapshot.getChildren()) { String ingridient = ds.getKey(); Log.d("TAG", ingridient); } } @Override public void onCancelled(DatabaseError databaseError) {} }; ingridientsRef.addListenerForSingleValueEvent(valueEventListener);
遇到的问题
日志中仅输出Ingridients,没有获取到IngridientIdOne、IngridientIdTwo下的目标keys,请问错误原因是什么?该如何实现需求?
错误原因分析
先帮你拆解问题:
- 你说日志只输出
Ingridients,这和你贴的代码逻辑不符——按照代码写法,遍历dataSnapshot.getChildren()应该拿到IngridientIdOne和IngridientIdTwo的key才对。大概率是测试时的代码与贴出的不一致(比如误写了Log.d("TAG", dataSnapshot.getKey())),或者数据库权限/路径拼写存在问题。 - 核心逻辑问题:就算你拿到了
IngridientIdOne和IngridientIdTwo的key,当前代码也没有深入到它们的子节点去获取食材keys——遍历只停留在ID节点这一层,没有继续往下遍历食材节点。
正确实现方案
下面给你两种靠谱的实现方式,按需选择:
方案一:一次性读取所有节点,分批次存入ArrayList
适合需要同时处理两个节点数据的场景:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference(); DatabaseReference ingridientsRef = rootRef.child("Receptes").child("Ingridients"); // 初始化存储食材的列表 ArrayList<String> idOneIngredients = new ArrayList<>(); ArrayList<String> idTwoIngredients = new ArrayList<>(); ValueEventListener valueEventListener = new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // 第一层遍历:拿到IngridientIdOne和IngridientIdTwo节点 for (DataSnapshot idSnapshot : dataSnapshot.getChildren()) { String currentId = idSnapshot.getKey(); // 判断当前是哪个ID节点,分别处理 if ("IngridientIdOne".equals(currentId)) { // 第二层遍历:获取该ID下的所有食材key for (DataSnapshot ingredientSnap : idSnapshot.getChildren()) { String ingredient = ingredientSnap.getKey(); idOneIngredients.add(ingredient); Log.d("TAG", "IngridientIdOne 食材:" + ingredient); } } else if ("IngridientIdTwo".equals(currentId)) { for (DataSnapshot ingredientSnap : idSnapshot.getChildren()) { String ingredient = ingredientSnap.getKey(); idTwoIngredients.add(ingredient); Log.d("TAG", "IngridientIdTwo 食材:" + ingredient); } } } // 数据处理完成,这里可以使用两个列表 Log.d("TAG", "IngridientIdOne 列表:" + idOneIngredients.toString()); Log.d("TAG", "IngridientIdTwo 列表:" + idTwoIngredients.toString()); } @Override public void onCancelled(DatabaseError databaseError) { // 一定要处理错误,方便排查问题 Log.e("TAG", "数据库读取失败:" + databaseError.getMessage()); } }; ingridientsRef.addListenerForSingleValueEvent(valueEventListener);
方案二:分别监听指定节点(更高效)
如果只需要这两个特定节点的数据,直接监听单个节点会更高效,避免读取多余数据:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference(); ArrayList<String> idOneIngredients = new ArrayList<>(); ArrayList<String> idTwoIngredients = new ArrayList<>(); // 监听IngridientIdOne节点 DatabaseReference idOneRef = rootRef.child("Receptes").child("Ingridients").child("IngridientIdOne"); idOneRef.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { for (DataSnapshot ds : dataSnapshot.getChildren()) { idOneIngredients.add(ds.getKey()); } Log.d("TAG", "IngridientIdOne 食材列表:" + idOneIngredients.toString()); } @Override public void onCancelled(DatabaseError databaseError) { Log.e("TAG", "读取IngridientIdOne失败:" + databaseError.getMessage()); } }); // 监听IngridientIdTwo节点 DatabaseReference idTwoRef = rootRef.child("Receptes").child("Ingridients").child("IngridientIdTwo"); idTwoRef.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { for (DataSnapshot ds : dataSnapshot.getChildren()) { idTwoIngredients.add(ds.getKey()); } Log.d("TAG", "IngridientIdTwo 食材列表:" + idTwoIngredients.toString()); } @Override public void onCancelled(DatabaseError databaseError) { Log.e("TAG", "读取IngridientIdTwo失败:" + databaseError.getMessage()); } });
额外注意事项
- 权限检查:确保你的Firebase数据库规则允许读取
Receptes/Ingridients节点,否则会导致onDataChange无法获取数据。 - 拼写一致性:节点名称的大小写、拼写必须和数据库里完全一致(比如
Ingridients和ingridients是两个不同的节点)。 - 错误处理:永远不要忽略
onCancelled方法,这里能帮你快速定位权限不足、网络异常等问题。
内容的提问来源于stack exchange,提问作者Felay
相关产品推荐
相关产品推荐

