Android 了解Firebase上的childEventListener是否已完成加载所有数据

Android 了解Firebase上的childEventListener是否已完成加载所有数据,android,firebase,firebase-realtime-database,Android,Firebase,Firebase Realtime Database,我正在使用Firebase实时数据库为我的Android应用程序存储和检索数据。在我的活动中,我使用childEventListener从Firebase检索所有数据(例如:用户数据列表) 我想显示一个进度条,只要数据没有完全从数据库中检索到。如何检查是否已完全检索所有数据,以便在加载数据后关闭进度条?有一种常见的方法可以检测Firebase何时在给定位置同步初始数据。此方法使用以下方法之一: 值事件始终在最后触发,并保证包含快照拍摄之前发生的任何其他事件的更新 因此,如果给定位置上同时有一个V

我正在使用Firebase实时数据库为我的Android应用程序存储和检索数据。在我的活动中,我使用
childEventListener
从Firebase检索所有数据(例如:用户数据列表)


我想显示一个进度条,只要数据没有完全从数据库中检索到。如何检查是否已完全检索所有数据,以便在加载数据后关闭进度条?

有一种常见的方法可以检测Firebase何时在给定位置同步初始数据。此方法使用以下方法之一:

值事件始终在最后触发,并保证包含快照拍摄之前发生的任何其他事件的更新

因此,如果给定位置上同时有一个
ValueEventListener
和一个
ChildEventListener
,则保证在所有
onchildaded()
调用完成后调用
ValueEventListener.onDataChange()
。您可以使用它来了解初始数据加载何时完成:

ref.addListenerForSingleValueEvent(new ValueEventListener() {
    public void onDataChange(DataSnapshot dataSnapshot) {
        System.out.println("We're done loading the initial "+dataSnapshot.getChildrenCount()+" items");
    }
    public void onCancelled(FirebaseError firebaseError) { }
});
ref.addChildEventListener(new ChildEventListener() {
    public void onChildAdded(DataSnapshot dataSnapshot, String previousKey) {
        System.out.println("Add "+dataSnapshot.getKey()+" to UI after "+previousKey);
    }
    public void onChildChanged(DataSnapshot dataSnapshot, String s) {
    }
    public void onChildRemoved(DataSnapshot dataSnapshot) {
    }
    public void onChildMoved(DataSnapshot dataSnapshot, String s) {
    }
    public void onCancelled(FirebaseError firebaseError) { }
});
在我的测试运行中,这将导致:

Add -K2WLjgH0es40OGWp6Ln to UI after null
Add -K2YyDkM4lUotI12OnOs to UI after -K2WLjgH0es40OGWp6Ln
Add -K2YyG4ScQMuRDoFogA9 to UI after -K2YyDkM4lUotI12OnOs
...
Add -K4BPqs_cdj5SwARoluP to UI after -K4A0zkyITWOrxI9-2On
Add -K4BaozoJDUsDP_X2sUu to UI after -K4BPqs_cdj5SwARoluP
Add -K4uCQDYR0k05Xqyj6jI to UI after -K4BaozoJDUsDP_X2sUu
We're done loading the initial 121 items
因此,您可以使用
onDataChanged()
事件隐藏进度条


但有一件事要记住:Firebase不只是加载数据。它不断地将数据从服务器同步到所有连接的客户端。因此,实际上没有任何时刻可以完全检索到数据。

我用非常简单的方法完成了这项工作。我让一个int计数,然后每当它进入函数时,我递增它并检查它是否等于child的总数。如果它相等,那么可以停止进度条

    int count = 0;    
    ref.addChildEventListener(new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s) {
            count++;


            if(count >= dataSnapshot.getChildrenCount()){
                //stop progress bar here
            }
        }
使用


听起来很奇怪。我刚刚添加了一个新项,只得到了:
在-K4uCQDYR0k05Xqyj6jI之后添加-K6ns123jl6xQXfQJR\u r到UI(如果您仍然体验到这种行为)(并且确定您只使用
addListenerForSingleValueEvent()添加侦听器)
,打开一个新问题,并包含重现问题所需的最少代码。如果您能在
onDataChange()
中执行
dataSnapshot.parent().getChildrenCount()
操作,那就太好了。我假设使用
addListenerForSingleValueEvent()
来获取项目数,将加载所有数据(刚刚加载到
onDataChange()
)中的内容?Rem:如果客户端缓存(android设备)中已有某些项,则此解决方案似乎不起作用。在这种情况下,onDataChange()事件在ChildEventListener完成同步服务器上的所有子项之前从缓存中检索元素!!这仅适用于第一次。缓存数据时onDataChange()调用First,但不会
ChildEventListener
获取所有子项,而不仅仅是添加的子项?因此,您将有两个重复集,一个来自
SingleValueEventListener
,另一个来自
ChildEventListener
。我的英语有点弱:以后如何摆脱listener?或者我们不必这样做抱歉,回复太晚了…:当您不需要侦听器时,您必须始终删除它们。您不应该删除的唯一侦听器是addListenerForSingleValueEvent(),它在事件触发时自动删除,但getChildrenCount()返回此查询的子项计数或节点的子项计数?因为如果是第二个,如果有筛选器,此方法将给出错误的答案。
  totalChilds = 0; 
  ref..addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    totalChilds = dataSnapshot.getChildrenCount();
                    ref.addChildEventListener(new ChildEventListener() {
                           @Override
                           public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
                           count++;
                           if(count >= totalChilds){
                                 progressDialog.dismiss();
            }
            @Override
        public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {

        }

        @Override
        public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {

        }

        @Override
        public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {

        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {

        }
    });

                }

                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) {

                }
            });