为何使用Query和ChildEventListener无法读取Firebase实时数据库数据
问题根因
你当前的代码问题出在多余的子节点遍历逻辑:
你构造的Query是查询HostID节点下所有Reference/ID等于用户输入值的子节点,onChildAdded返回的dataSnapshot本身就已经是匹配到的HostID下的完整业务节点(对应你数据库结构里HostID下的uid/pushkey级节点,包含Reference、HostLocation、TrackingID所有子字段)。
你额外遍历dataSnapshot.getChildren()后,拿到的是Reference、HostLocation、TrackingID这些单个子节点,在这些子节点中读取HostLocation、TrackingID等字段自然会失败,导致取不到TrackingID下的对应数据。
你的数据库结构参考:
修复代码
直接去掉onChildAdded中的for循环即可,修改后的完整逻辑如下:
private void isTrackingID() { String userTrackingID = enterTracking.getText().toString().trim(); Toast.makeText(this, "Tracking ID = " + userTrackingID, Toast.LENGTH_SHORT).show(); DatabaseReference reference = FirebaseDatabase.getInstance().getReference("HostID"); Query query = reference.orderByChild("Reference/ID").equalTo(userTrackingID); query.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String previousChildName) { if (dataSnapshot.exists()) { Log.i("checking", "this is value message"); enterTracking.setError(null); // 直接从当前dataSnapshot读取字段,无需遍历子节点 latitudefromDatabase = String.valueOf(dataSnapshot.child("HostLocation").child("latitude").getValue()); Log.i("testing for latitude", latitudefromDatabase); longitudefromDatabase = String.valueOf(dataSnapshot.child("HostLocation").child("longitude").getValue()); Log.i("testing for longitude", longitudefromDatabase); String hostUID = String.valueOf(dataSnapshot.child("Reference").child("uid").getValue()); String customerAddress = String.valueOf(dataSnapshot.child("TrackingID").child(userTrackingID).child("customerAddress").getValue()); String customerReplyStatus = String.valueOf(dataSnapshot.child("TrackingID").child(userTrackingID).child("customerReplyStatus").getValue()); String id = String.valueOf(dataSnapshot.child("TrackingID").child(userTrackingID).child("id").getValue()); String latitude = String.valueOf(dataSnapshot.child("TrackingID").child(userTrackingID).child("latitude").getValue()); String longitude = String.valueOf(dataSnapshot.child("TrackingID").child(userTrackingID).child("longitude").getValue()); String status = String.valueOf(dataSnapshot.child("TrackingID").child(userTrackingID).child("status").getValue()); Intent intent = new Intent(getApplicationContext(), MapsActivity.class); intent.putExtra("hostUID", hostUID); intent.putExtra("hostlatitude", latitudefromDatabase); intent.putExtra("hostlongitude", longitudefromDatabase); intent.putExtra("customerAddress",customerAddress); intent.putExtra("customerReplyStatus",customerReplyStatus); intent.putExtra("id",id); intent.putExtra("latitude",latitude); intent.putExtra("longitude",longitude); intent.putExtra("status",status); // 避免重复跳转可添加FLAG_ACTIVITY_SINGLE_TOP标记 intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); startActivity(intent); } else { enterTracking.setError("Invalid Tracking ID from database"); enterTracking.requestFocus(); } } @Override public void onChildChanged(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) { // 数据库数据更新时触发,复用onChildAdded的读取逻辑即可 // 如果不需要每次更新都跳转页面,建议把监听移到MapsActivity内部 if (snapshot.exists()) { // 此处可编写数据更新后的处理逻辑,比如发送本地广播通知MapsActivity更新UI } } @Override public void onChildRemoved(@NonNull DataSnapshot snapshot) { // 对应节点被删除时的处理逻辑 } @Override public void onChildMoved(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) { // 节点排序变更时的处理逻辑,当前场景不需要可留空 } @Override public void onCancelled(@NonNull DatabaseError error) { // 补充错误日志,方便排查权限、数据库规则问题 Log.e("firebase_query", "查询失败: " + error.getMessage()); } }); }
优化建议(解决地图页面重复刷新问题)
你之前用ValueEventListener出现的页面刷新问题,本质是每次拿到全量数据都重新启动Activity导致的,和用哪种监听器无关。更合理的实现方式是:
- 跳转时只把需要监听的节点key(即
dataSnapshot.getKey())传给MapsActivity - 在MapsActivity内部给对应节点加ChildEventListener/ValueEventListener,拿到更新数据后直接修改地图标记、更新UI,不需要重新跳转页面,性能更好也不会出现整体刷新的问题。
内容的提问来源于stack exchange,提问作者EXCITED AID
相关产品推荐
相关产品推荐

