代码之家  ›  专栏  ›  技术社区  ›  DeveloperKurt

android-使用Firebase从列表中查询每个节点的密钥

  •  1
  • DeveloperKurt  · 技术社区  · 6 年前

    我有一个字符串列表,这个列表包含Firebase数据库中的节点名。

    正因为如此,我需要检索所有数据,所以在检索某些数据时添加到列表中不是一个选项。

    然而,问题开始于Firebase的异步结构。

    我遍历自定义列表中的每个节点名,并在该循环下在Firebase`thread(addListenerForSingleValueEvent)中创建另一个循环来检索所有键。 但它是异步工作的。我试着用线程和信号量把它改成同步的,但是没有成功。

    如果任务可以在这种情况下使用,它是如何使用的,或者有其他解决方案吗?

    private void getKeysFromNodeList(final FirebaseDataRetrieveListener listener) //TODO [BUG] when first for loop initializes it ignores the seperate thread in the inner anonymous class so it'll be already finished it's cycle before Firebase` loop starts...
        {
            listener.onStart();
    
                    final DatabaseReference databaseRef = firebaseInstance.rootRef.child(context.getString(R.string.databaseref));
                    for (iterator = 0; iterator < nodeList.size(); iterator ++)
                        {
    
                            Query query = databaseRed.child(nodeList.get(iterator));
    
                            query.addListenerForSingleValueEvent(new ValueEventListener()
                                {
                                    @Override
                                    public void onDataChange(@NonNull DataSnapshot dataSnapshot)
                                        {
    
    
                                            for (DataSnapshot snap : dataSnapshot.getChildren())
                                                {
    
                                                    iterator++;
    
                                                    String key= snap.getKey();
                                                    // I've done my jobs with given key here
    
    
                                                    // if got the last key from node and iterated the last node
                                                    if (firebaseIterator== dataSnapshot.getChildrenCount() - 1 && iterator == nodeList.size() - 1)
                                                        {
    
    
                                                            firebaseIterator= 0;// reset the iterators
                                                            iterator= 0;
    
                                                            listener.onSuccess();
                                                            break;
                                                        }
                                                    // if got the last key from node
                                                    else if (firebaseIterator== dataSnapshot.getChildrenCount() - 1)
                                                        {
                                                            firebaseIterator= 0; // reset the iterator
    
                                                            break;
                                                        }
                                                }
                                        }
    
                                    @Override
                                    public void onCancelled(@NonNull DatabaseError databaseError)
                                        {
                                            listener.onFailed(databaseError);
                                            return;
                                        }
                                });
    
    
                        }
                    ;
    
    
                } 
    
        }
    

    FirebaseDataRetrieveListener.java文件

    public interface FirebaseDataRetrieveListener
    {
        public void onStart();
        public void onSuccess();
        public void onFailed(DatabaseError databaseError);
    }
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   Alex Mamo    6 年前

    Firebase API是 onDataChange() 方法在被调用后立即返回,它返回的任务的回调将在一段时间后被调用。我们不能保证要花多长时间。因此,在数据可用之前可能需要几百毫秒到几秒钟。因为该方法会立即返回,所以还没有从回调中填充来自数据库的值。

    post 其中我解释了如何使用自定义回调来完成。你也可以看看这个 video 为了更好的理解。

    总之,没有办法像Firebase那样将异步API转换为同步API。

        2
  •  1
  •   DeveloperKurt    6 年前

    为了解决这个问题,我使我的方法递归并使用了一个侦听器。 在我的解决方案中,我们将跟踪我们调用递归方法的次数,以及Firebase循环到给定节点的键的次数,以检测我们是否到达节点的末尾,并循环列表中的所有节点。

    在类的作用域中声明2个迭代器和1个侦听器。

            private RecursiveListener listener;
            private long firebaseIterator = 0;
            private int recursiveIterator = 0;
    
            public interface getKeysFromNodeListListener
                {
                    void onFinished();
                }
    

    我们将使用递归监听器来获得是否已完成递归函数的通知。

    当我们遍历所有节点和它们的密钥时,会调用onFinished。

    private  void getKeysFromNodeList(final getKeysFromNodeListListener listener)
            {
    
    final DatabaseReference databaseRef = firebaseInstance.rootRef.child(database_reference);
    
                        if (recursiveIterator < nodesList.size())
                            {
    
                                Query query = databaseRef.child(nodesList.get(recursiveIterator));
                                query.addListenerForSingleValueEvent(new ValueEventListener()
                                    {
                                        @Override
                                        public void onDataChange(@NonNull DataSnapshot dataSnapshot)
                                            {
                                                for (DataSnapshot snap : dataSnapshot.getChildren())
                                                    {
                                                        firebaseIterator++;
    
    
                                                        //Do you job with the current key
                                                        String key = snap.getKey();
                                                        keysList.add(key);
    
                                                        // if got the last key from key and iterated the last node
                                                        if (firebaseIterator == dataSnapshot.getChildrenCount()  && recursiveIterator == nodeList.size() -1)
                                                            {
                                                                firebaseIterator = 0;// reset the iterators
                                                                recursiveIterator = 0;
                                                                return;
                                                            }
                                                        // if got the last key from current node
                                                        else if (firebaseIterator == dataSnapshot.getChildrenCount() )
                                                            {
                                                                recursiveIterator++;  // increase the recursive iterator because we looped through all the keys under the current node
                                                                firebaseIterator = 0; // reset the recursiveIterator because we gonna need to loop again with default value
                                                                getKeysFromNodeList(listener);  // call the same method
                                                            }
                                                    }
                                            }
    
                                        @Override
                                        public void onCancelled(@NonNull DatabaseError databaseError)
                                            {
                                                Log.e(TAG, "Firebase query failed " + databaseError);
                                                return;
                                            }
                                    });
                            }
                    }
    

    在使用该方法时,首先创建一个侦听器并重写onFinished(),然后调用该方法。

       listener = new getKeysFromNodeListListener()
                                        {
                                            @Override
                                            public void onFinished()
                                                {
    
                                                 // Do whatever you gonna do after you got all the keys from all nodes.
                                                }
                                        };
                                     getKeysFromNodeList(listener);