Получить данные из базы данных в реальном времени с помощью обратного вызова действия - PullRequest
0 голосов
/ 16 ноября 2018

Я пытаюсь получить значение JSON из базы данных реального времени Firebase, используя Unity.

Я делаю следующее:

   FirebaseDatabase.DefaultInstance
          .GetReference("Leaders").OrderByChild("score").GetValueAsync().ContinueWith(task =>
                    {
                        if (task.IsFaulted)
                        {
                            Debug.LogError("error in reading LeaderBoard");
                            return;
                        }
                        else if (task.IsCompleted)
                        {
                            Debug.Log("Received values for Leaders.");
                            string JsonLeaderBaord = task.Result.GetRawJsonValue();
                            callback(JsonLeaderBaord);
                        }
        }
  });

Пытается прочитать CallBack:

private string GetStoredHighScores()
    {
      private string JsonLeaderBoardResult;
      DataBaseModel.Instance.RetriveLeaderBoard(result =>
            {
                JsonLeaderBoardResult = result; //gets the data

            });
  return JsonLeaderBoardResult; //returns Null since it doesn't wait for the result to come.
}

Вопрос в том, как мне ждать обратного вызова, чтобы вернуть значение, а потом return значение JsonLeaderBoardResult.

Ответы [ 2 ]

0 голосов
/ 16 ноября 2018

return JsonLeaderBoardResult; // возвращает значение Null, поскольку оно не ожидает получения результата.

Функция RetriveLeaderBoard не возвращается немедленно.Вы можете либо использовать сопрограмму, чтобы дождаться ее, либо вернуть результат JsonLeaderBoardResult через Action.Использование Action более целесообразно в вашем случае.

Измените тип возвращаемого значения строки на void, затем верните результат через Action:

private void GetStoredHighScores(Action<string> callback)
{
    string JsonLeaderBoardResult;
    DataBaseModel.Instance.RetriveLeaderBoard(result =>
            {
                JsonLeaderBoardResult = result; //gets the data
                if (callback != null)
                    callback(JsonLeaderBoardResult);
            });
}

Использование:

GetStoredHighScores((result) =>
{
    Debug.Log(result);
});

РЕДАКТИРОВАТЬ:

Это здорово, но все равно нужно что-то делать после получения результата в GetStoredHighScores вне действия, в противном случае я могу получить ошибку вроде: get_transform может быть вызван только из основного потока.

Вы получаете эту ошибку, потому что RetriveLeaderBoard выполняется из другого потока.Возьмите UnityThread из этой записи, затем сделайте обратный вызов в главной теме с UnityThread.executeInUpdate.

Ваш новый код:

void Awake()
{
    UnityThread.initUnityThread();
}

private void GetStoredHighScores(Action<string> callback)
{
    string JsonLeaderBoardResult;
    DataBaseModel.Instance.RetriveLeaderBoard(result =>
            {
                JsonLeaderBoardResult = result; //gets the data

                UnityThread.executeInUpdate(() =>
                {
                    if (callback != null)
                        callback(JsonLeaderBoardResult);
                });
            });
}
0 голосов
/ 16 ноября 2018

Вы видите классическую путаницу с асинхронными API.Поскольку загрузка данных из Firebase может занять некоторое время, это происходит асинхронно (в отдельном потоке).Это позволяет вашему основному коду продолжить работу, пока клиент Firebase ожидает ответа от сервера.Когда данные доступны, клиент Firebase вызывает ваш метод обратного вызова с этими данными, чтобы вы могли их обработать.

Проще всего увидеть, что это делает в вашем коде, поместив несколько операторов регистрации:

Debug.Log("Before starting to load data");
FirebaseDatabase.DefaultInstance
      .GetReference("Leaders").OrderByChild("score").GetValueAsync().ContinueWith(task => {
    Debug.Log("Got data");

    }
});
Debug.Log("After starting to load data");

Когда вы запускаете этот код, он печатает:

Перед началом загрузки данных

После начала загрузки данных

Получил данные

Вероятно, это не тот порядок, в котором вы ожидали вывод.Из-за асинхронного характера вызова Firebase вторая строка журнала печатается последней.Это точно объясняет, почему вы видите пустой массив при его возврате: к тому времени данные еще не были загружены из Firebase, а ваш ContinueWith еще не выполнен.

Решение дляэто всегда одно и то же: так как вы не можете вернуть данные, которые еще не загружены, вы должны реализовать функцию обратного вызова.Код, которым вы поделились, уже делает это дважды: один раз для ContinueWith самой Firebase и один для RetriveLeaderBoard.

Любой код, которому требуется актуальная таблица лидеров, по сути должен будет вызвать RetriveLeaderBoard и делать любую работу с данными списка лидеров в обратном вызове.Например, если вы хотите распечатать таблицу лидеров:

DataBaseModel.Instance.RetriveLeaderBoard(result => {
    Debug.Log(result);
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...