【问题标题】:Cloud Firestore GetSnapshotAsync to return a value. Unity and C#Cloud Firestore GetSnapshotAsync 以返回一个值。统一和 C#
【发布时间】:2020-06-26 23:17:34
【问题描述】:

我正在尝试创建一个类来管理我的 Cloud Firestore 请求(就像任何 SQLiteHelper 类一样)。但是,firebase 使用异步调用,我无法将值返回给其他脚本。 这里是一个例子(布尔返回):

    public bool CheckIfIsFullyRegistered(string idUtente)
    {
        DocumentReference docRef = db.Collection("Utenti").Document(idUtente);
        docRef.GetSnapshotAsync().ContinueWithOnMainThread(task =>
        {
            DocumentSnapshot snapshot = task.Result;
            if (snapshot.Exists)
            {                
                Debug.Log(String.Format("Document {0} exist!", snapshot.Id));
                return true; //Error here
            }
            else
            {
                Debug.Log(String.Format("Document {0} does not exist!", snapshot.Id));
            }
        });
    }

【问题讨论】:

    标签: c# firebase unity3d asynchronous


    【解决方案1】:

    不幸的是,由于 Firestore 充当一些运行缓慢的 I/O(磁盘访问或 Web 请求)的前端,因此您与之进行的任何交互都需要是异步的。在执行此访问时,您还需要尽可能避免阻塞您的游戏循环。也就是说不会同步调用GetSnapshotAsync

    现在您有两种选择来编写感觉同步的代码(如果您像我一样,这样想比使用回调或反应结构更容易)。

    首先是GetSnapshotAsync返回一个任务。您可以在 async 函数中选择 await 执行该任务:

    public async bool CheckIfIsFullyRegistered(string idUtente)
    {
        DocumentReference docRef = db.Collection("Utenti").Document(idUtente);
    
        // this is equivalent to `task.Result` in the continuation code
        DocumentSnapshot snapshot = await docRef.GetSnapshotAsync()
        return snapshot.Exists;
    }
    

    问题在于async/await 对 C# 对象生命周期做出了一些假设,这些假设在 Unity 上下文中无法保证(更多信息在我的相关@​​987654321@ 和video 中)。如果您是一名长期的 Unity 开发人员,或者只是想避免 this == null 成为真实的,您可以选择将您的异步调用包装在 WaitUntil 块中:

    private IEnumerator CheckIfIsFullyRegisteredInCoroutine() {
        string idUtente;
    
        // set idUtente somewhere here
    
        var isFullyRegisteredTask = CheckIfIsFullyRegistered(idUtente);
        yield return new WaitUntil(()=>isFullyRegisteredTask.IsComplete);
        
        if (isFullyRegisteredTask.Exception != null) {
            // do something with the exception here
            yield break;
        }
    
        bool isFullyRegistered = isFullyRegisteredTask.Result;
    }
    

    我喜欢使用的另一种模式是to use listeners,而不仅仅是检索快照。我将使用来自 Firestore(或 RTDB)的任何最新数据填充一些 Unity 端类,并让我的所有 Unity 对象 ping MonoBehaviour。这特别适合 Unity's new ECS architecture 或您在每帧基础上查询数据的任何时候。

    希望对大家有所帮助!

    【讨论】:

    • 正是我正在寻找的。非常感谢帕特里克! (我们是你在 youtube 和 firebase 上的忠实粉丝!)
    • 太棒了!我喜欢做这些,所以很高兴听到它们很有帮助。
    【解决方案2】:

    这就是我让它工作的方式,但请原谅我的无知,因为我只使用了 FBDB 一周。

    这是一个sn-p,希望对某人有所帮助。

    为我们的登录事件创建一个线程任务扩展

        static Task DI = new System.Threading.Tasks.Task(LoginAnon);
    

    匿名登录

    DI = FirebaseAuth.DefaultInstance.SignInAnonymouslyAsync().ContinueWith(result =>
        {
            Debug.Log("LOGIN [ID: " + result.Result.UserId + "]");
            userID = result.Result.UserId;
            FirebaseDatabase.DefaultInstance.GetReference("GlobalMsgs/").ChildAdded += HandleNewsAdded;
            FirebaseDatabase.DefaultInstance.GetReference("Users/" + userID + "/infodata/nickname/").ValueChanged += HandleNameChanged;
            FirebaseDatabase.DefaultInstance.GetReference("Users/" + userID + "/staticdata/status/").ValueChanged += HandleStatusChanged;
            FirebaseDatabase.DefaultInstance.GetReference("Lobbies/").ChildAdded += HandleLobbyAdded;
            FirebaseDatabase.DefaultInstance.GetReference("Lobbies/").ChildRemoved += HandleLobbyRemoved;
            loggedIn = true;
        });
    

    然后获取值。

                DI.ContinueWith(Task =>
            {
                FirebaseDatabase.DefaultInstance.GetReference("Lobbies/" + selectedLobbyID + "/players/").GetValueAsync().ContinueWith((result) =>
                {
                    DataSnapshot snap2 = result.Result;
                    Debug.Log("Their nickname is! -> " + snap2.Child("nickname").Value.ToString());
                    Debug.Log("Their uID is! -> " + snap2.Key.ToString());
    
                    //Add the user ID to the lobby list we have
                    foreach (List<string> lobbyData in onlineLobbies)
                    {
                        Debug.Log("Searching for lobby:" + lobbyData[0]);
                        if (selectedLobbyID == lobbyData[0].ToString()) //This is the id of the user hosting the lobby
                        {
                            Debug.Log("FOUND HOSTS LOBBY ->" + lobbyData[0]);
                            foreach (DataSnapshot snap3 in snap2.Children)
                            {
                                //add the user key to the lobby
                                lobbyData.Add(snap3.Key.ToString());
                                Debug.Log("Added " + snap3.Child("nickname").Value.ToString() + " with ID: " + snap3.Key.ToString() + " to local lobby.");
                                currentUsers++;
                            }
                            return;
                        }
                    }
                });
            });
    

    显然你可以随心所欲地改变它,它并不真正需要循环,但在我将代码压缩成更易读和更直观的代码之前,我正在使用它们进行测试。

    【讨论】:

      猜你喜欢
      • 2020-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-20
      相关资源
      最近更新 更多