Android - запрос ключей каждого узла из списка с помощью Firebase - PullRequest
0 голосов
/ 13 октября 2018

У меня есть список строк, и этот список содержит имена узлов в базе данных Firebase.

И у меня есть собственный метод сортировки, поэтому я хочу получить все ключи для каждого узла в моем пользовательском списке безиспользуя функции сортировки запросов Firebase`.И из-за этого мне нужно получить все данные, поэтому добавление в список при получении некоторых данных не вариант.

Однако проблема начинается с асинхронной структуры Firebase.

Я повторяючерез каждое имя узла в моем настраиваемом списке и под этим циклом я создаю еще один цикл в потоке Firebase` (addListenerForSingleValueEvent), чтобы получить все ключи.Но это работает асинхронно.Я пытался изменить его на синхронный, используя Thread и Semaphore, но это не сработало.Я также использовал пользовательский интерфейс (FirebaseDataRetrieveListener), чтобы указать, когда завершается цикл в valueEventListener, но так как valueEventListener мгновенно возвращает это, это невозможно без остановки потока.

Если Задача может использоваться в этой ситуации, как это может быть, или есть ли другие решения?

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 ]

0 голосов
/ 17 октября 2018

Чтобы решить эту проблему, я сделал свой метод рекурсивным и использовал слушателя.В моем решении мы будем следить за тем, сколько раз мы вызывали рекурсивный метод и сколько раз Firebase перебирал петли на ключах данного узла, чтобы определить, достигаем ли мы до конца узла и зациклили ли мы все узлы вlist.

Объявите 2 итератора и 1 слушателя в области видимости вашего класса, например.

        private RecursiveListener listener;
        private long firebaseIterator = 0;
        private int recursiveIterator = 0;

        public interface getKeysFromNodeListListener
            {
                void onFinished();
            }

Мы собираемся использовать рекурсивный слушатель, чтобы получить уведомление о завершении нашей рекурсивной функции.

Перед вызовом вашего метода определите слушателя и переопределите 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);
0 голосов
/ 14 октября 2018

По сути, вы пытаетесь вернуть значение синхронно из API, который является асинхронным.Это не очень хорошая идея.Вы должны обращаться с API асинхронно, как и предполагалось.Приостановка потока может решить вашу проблему, но только частично.и он вообще не рекомендуется.

API Firebase асинхронный , что означает, что метод onDataChange() возвращается сразу после его вызова, и обратный вызов из Задачи, которую он возвращает, будет вызван некоторое времяпотом.Там нет никаких гарантий о том, сколько времени это займет.Таким образом, получение этих данных может занять от нескольких сотен миллисекунд до нескольких секунд.Поскольку этот метод немедленно возвращается, значения, поступающие из базы данных, еще не будут заполнены из обратного вызова.

Для быстрого решения этой проблемы будет использовать эти значения только внутри обратного вызова, в противном случае я рекомендуюВы видите последнюю часть моего ответа от этого поста , в котором я объяснил, как это можно сделать с помощью пользовательского обратного вызова.Вы также можете взглянуть на это видео для лучшего понимания.

В заключение, нет способа превратить асинхронный API, поскольку Firebase превращается всинхронный.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...