Обработка Firebase «Задач» и реализация классов диспетчера (для Firebase) в Unity - PullRequest
0 голосов
/ 02 апреля 2019

Я пишу код для игры, серверная часть которой полностью основана на Firebase.Я ожидаю использовать в игре функции аутентификации, базы данных, InstanceID, обмена сообщениями и облака.Будучи начинающим программистом C #, я впервые столкнулся с C # «Задачами» с Firebase.Я собираюсь использовать базу данных много раз (например, обновление счета, запросы друзей, чат, друзья сделали это, друзья сделали это).В основном я чувствую себя комфортно с Singleton Pattern (GameManagers, EnemyManagers, SoundManagers и т. Д.).Но с Firebase, так как большинство его вызовов являются асинхронными и реализуются с помощью задач.Я думаю, что мне нужно обходиться иначе, чтобы реализовать менеджеров.

Например, мне нужно отправить запрос о дружбе конкретному другу.UIManager - это сценарий, который обрабатывает события пользовательского интерфейса и т. Д. Я бы хотел вызвать метод из этого сценария другому менеджеру (скажем FriendsManager).Но мне нужно сначала проверить, является ли этот друг моим другом из базы данных или нет?Итак, что бы я сделал, это

class UIManager
{
   void OnFriendRequestClicked(string friendId)
   {
      bool userExists = FriendsManager.instance.UserExists(friendId);
      if(userExists)
            // Proceed with Sending Request
               FriendsManager.instance.SendRequest(friendId);
       else 
          // Show a Dialogue that User ID is invalid
          ShowError("User Id is invalid");

       // NOTE: The above code block of "condition" is executed before 
       // the UserID is validated from FriendsManager
       // I know its because of Task. But how can I alter this code 
       // to do something in the similar pattern? 
   }
}

class FriendsManager
{
   bool UserExists(string userIdToCheck)
   {
    reference.Child("users").Child(userIdToCheck).GetValueAsync().ContinueWith(
  task=>
   {
       if(task.IsCompleted)
         {
             if(task.Result == null)
                  return false;    // (expected) Return false to Method "UserExists"
             else 
                  return true;    //(expected) Return true to Method "UserExists" 

       // But this won't actually return "bool" to the method,
      // it actually returns to its own "Task"
     //NOTE: -> How to Return from here to the Method? 
   )};   
}

1 Ответ

1 голос
/ 02 апреля 2019

Данные загружаются из Firebase асинхронно.Вместо ожидания / блокировки во время загрузки данных приложение продолжается.А затем, когда данные доступны, он вызывает ваш обратный вызов.

Это легче всего увидеть с помощью некоторых операторов ведения журнала:

Debug.Log("Before starting to load data");

reference.Child("users").Child(userIdToCheck).GetValueAsync().ContinueWith(task=> {
   Debug.Log("Data loaded");
});

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

Когда вы запускаете этот код, он записывает в журнал:

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

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

Загрузка данных

Это, вероятно, не то, что вы ожидали, но объясняет отличнопочему вы не можете вернуть значение из обратного вызова: UserExists уже завершился на этом этапе.

Это означает, что любой код, которому требуется доступ к данным из базы данных, должен иметь значение внутри блока ContinueWith (или вызываться оттуда).


Самый простой подход - переместить код из вашего OnFriendRequestClicked в UserExists:

bool UserExists(string userIdToCheck) {
  reference.Child("users").Child(userIdToCheck).GetValueAsync().ContinueWith(task=>
{
   if(task.IsCompleted)
   {
       if(task.Result == null)
           ShowError("User Id is invalid");
       else 
           FriendsManager.instance.SendRequest(friendId);
   )};   
}

Затем вы можете вызвать эту функцию без if после нее.


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

Например, используя Task:

bool UserExists(string userIdToCheck, Action<bool> callback) {
  reference.Child("users").Child(userIdToCheck).GetValueAsync().ContinueWith(task=>
{
   if(task.IsCompleted)
   {
       if(task.Result == null)
           callback(false);
       else 
           callback(true);
   )};   
}

И затем вызвать его:

FriendsManager.instance.UserExists(friendId, userExists => {
    if(userExists)
        FriendsManager.instance.SendRequest(friendId);
    else 
        ShowError("User Id is invalid");
})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...