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

标签 android firebase asynchronous firebase-realtime-database

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

我有一个自定义排序方法,因此我想在不使用 Firebase 查询排序函数的情况下获取自定义列表中每个节点的所有键。 因此,我需要检索所有数据,因此在检索某些数据时添加到列表不是一种选择。

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

我遍历自定义列表中的每个节点名称,并在该循环下在 Firebase 线程 ( addListenerForSingleValueEvent ) 中创建另一个循环以检索所有键。 但它是异步工​​作的。我试图通过使用 Thread 和 Semaphore 将其更改为同步,但没有成功。 我还使用了自定义接口(interface) (FirebaseDataRetrieveListener) 来指示 valueEventListener 中的循环何时结束,但是由于 valueEventListener 立即返回,所以如果不暂停线程这是不可能的。

如果Task's可以在这种情况下使用,怎么可能,或者有没有其他解决方案?

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);
}

最佳答案

基本上,您正在尝试从异步 API 同步返回一个值。那不是一个好主意。您应该按预期异步处理 API。暂停线程可能会解决您的问题,但只是部分解决。并且根本不推荐。

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

快速解决此问题的方法是仅在回调中使用这些值,否则我建议您从这个 post 中查看我的答案的最后一部分。 我在其中解释了如何使用自定义回调来完成。你也可以看看这个 video 以便更好地理解。

总而言之,无法将异步 API 转换为同步 API,因为 Firebase 是同步 API。

关于android - 使用 Firebase 从列表中查询每个节点的键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52794708/

相关文章:

java - 如何从 Firebase 存储获取 URL getDownloadURL

c - Linux,套接字,非阻塞连接

javascript - Promise.resolve 是异步函数吗?

java - picasso 加载图像后将图像保存在SD卡中

Android:firebase 的电子邮件帐户注册失败

java - 使用 'android-vision'库保存实时检测到的人脸(Track Faces)图像

swift - 如何在 Firestore (Swift) 中存储数据

python - 将 yield 与多个 ndb.get_multi_async 一起使用

android - x264可以在Android上执行音频录制工作吗

android - Dagger 不允许我在一个类中使用两个相同类型的对象