在Unity中处理Firebase“任务”并实现Manager类(用于Firebase)

时间:2019-04-02 10:52:15

标签: c# firebase unity3d design-patterns firebase-realtime-database

我正在为服务器端完全基于Firebase的游戏编写代码。我希望在游戏中使用Auth,数据库,InstanceID,消息传递和云函数。 作为C#的新手,我第一次在Firebase中遇到了C#“任务”。 我将使用数据库很多次(例如“分数更新”,“好友请求”,“聊天”,“朋友做到了”,“朋友做到了”)。 我通常对Singleton Pattern(GameManager,EnemyManager,SoundManager等)感到满意。 但是使用Firebase,因为它的大多数调用是异步的,并且是通过Tasks实现的。我认为我需要采取不同的解决方法来实施Manager。

例如,我需要向特定朋友发送“朋友请求”。 UIManager是处理UI事件等的脚本。我想从此脚本调用Method到另一个Manager(例如,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 个答案:

答案 0 :(得分:1)

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