Android Studio如何获取for循环内字符串变量供Firebase外部查询使用
原始问题代码
final DatabaseReference reference=FirebaseDatabase.getInstance().getReference("Client"); reference.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { for (DataSnapshot snapshot1:snapshot.child("c_orders").getChildren()){ final String rt=snapshot1.getKey().toString(); } } @Override public void onCancelled(@NonNull DatabaseError error) { } }); FirebaseRecyclerOptions<client_model_btncheckorders> options2 = new FirebaseRecyclerOptions.Builder<client_model_btncheckorders>() .setQuery(FirebaseDatabase.getInstance().getReference().child("Client").child("c_orders").child(rt).child("check_orders"), client_model_btncheckorders.class) .build(); adapter2=new adapter_clientside_checkbtn(options2); recyclerView2.setAdapter(adapter2); return view; }
核心问题
- 变量
rt是addValueEventListener异步回调内的局部变量,回调外的代码执行时回调还没触发,既访问不到变量,也拿不到正确值 FirebaseRecyclerAdapter只能绑定单个查询路径,无法直接适配多节点遍历查询的场景,直接在循环里创建适配器会导致重复初始化、列表异常- 数据加载需要由其他RecyclerView的按钮点击触发,需要控制加载时机
可行解决方案
方案1:改用普通RecyclerView适配器,手动汇总多节点数据(适配现有数据结构,改动最小)
- 首先在页面/Fragment的成员变量位置定义公共存储对象,不要把变量定义在方法内部:
// 存储所有c_orders下的节点key private List<String> orderUserKeys = new ArrayList<>(); // 适配器只初始化一次,不要重复创建 private adapter_clientside_checkbtn adapter2; private RecyclerView recyclerView2;
- 页面初始化阶段先拉取所有c_orders下的key,存入成员变量列表:
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Client"); reference.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { orderUserKeys.clear(); for (DataSnapshot snapshot1 : snapshot.child("c_orders").getChildren()){ String rt = snapshot1.getKey(); orderUserKeys.add(rt); } } @Override public void onCancelled(@NonNull DatabaseError error) { // 按需添加错误处理逻辑 } }); // 初始化适配器和RecyclerView,这里只执行一次 adapter2 = new adapter_clientside_checkbtn(); recyclerView2.setAdapter(adapter2); // 注意把原来的FirebaseRecyclerAdapter改成继承ListAdapter的普通适配器,支持submitList更新数据
- 在触发加载的按钮点击事件中,遍历所有key拉取对应数据,全部加载完成后统一刷新列表:
// 其他RecyclerView内的按钮点击监听 loadOrderBtn.setOnClickListener(v -> { List<client_model_btncheckorders> allOrders = new ArrayList<>(); final int[] finishCount = {0}; int totalCount = orderUserKeys.size(); if (totalCount == 0) { adapter2.submitList(allOrders); return; } for (String rt : orderUserKeys) { DatabaseReference checkOrderRef = FirebaseDatabase.getInstance().getReference() .child("Client").child("c_orders").child(rt).child("check_orders"); checkOrderRef.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { for (DataSnapshot orderSnap : snapshot.getChildren()) { client_model_btncheckorders order = orderSnap.getValue(client_model_btncheckorders.class); allOrders.add(order); } finishCount[0]++; // 所有节点数据加载完成后刷新UI if (finishCount[0] == totalCount) { adapter2.submitList(allOrders); } } @Override public void onCancelled(@NonNull DatabaseError error) { finishCount[0]++; if (finishCount[0] == totalCount) { adapter2.submitList(allOrders); } } }); } });
方案2:调整数据库结构,适配FirebaseRecyclerAdapter
如果不想手动处理多节点拉取逻辑,可以调整数据存储结构:新建一个公共节点比如all_check_orders,把所有用户的check_orders数据都同步存到这个节点下,每个订单条目带上所属用户的标识字段。
这种场景下只需要绑定这一个公共节点的查询就能构建FirebaseRecyclerOptions,不需要循环遍历多个rt,直接用FirebaseUI的适配器即可,后续数据更新也能自动监听刷新。
注意事项
- 禁止在循环内重复创建RecyclerView适配器,适配器全局只初始化一次,后续只更新数据源即可,否则会出现内存泄漏、列表滑动错位、数据不显示的问题
- Firebase的数据库读取是异步操作,不要在回调外部直接访问回调内赋值的变量,要么把后续逻辑写到回调内,要么等回调执行完成、数据存入成员变量后再通过点击事件等明确时机触发后续逻辑
内容的提问来源于stack exchange,提问作者Akash
相关产品推荐
相关产品推荐

