【问题标题】:How do I properly block code execution until callback如何正确阻止代码执行直到回调
【发布时间】:2019-08-22 10:28:14
【问题描述】:

我是 Unity 和 C# 的新手,并尝试查询我的 Firebase 实时数据库,但代码不会阻止回调完成。

我尝试过实现回调,但这似乎不起作用。

static public void ReadFromDb(int level, Action<int> callback) 
{
    int return_value = -1;
    string sessionId = PlayerPrefs.GetString("SessionID");

    FirebaseDatabase.DefaultInstance.GetReference("users/"+sessionId).GetValueAsync().ContinueWith(task => {
        if (task.IsFaulted) 
        {
            // Handle the error...
            Debug.Log("Task faulted");
            callback(return_value);
        } 
        else if (task.IsCompleted) 
        {
            DataSnapshot snapshot = task.Result;
            string score_string = (snapshot.Child(level.ToString()).Value).ToString();
            Debug.Log("score_string " + score_string);
            return_value = int.Parse(score_string);
            callback(return_value);
        }
    });
}


public void LevelComplete() 
{
    DatabaseCode.writeDatabase(SceneManager.GetActiveScene().buildIndex + 1, counter);
    DatabaseCode.ReadFromDb(SceneManager.GetActiveScene().buildIndex + 1, (result) => {
        prevlevelscore = result;
        Debug.Log("result " + result.ToString());
    });
    prevscore = prevlevelscore;
    Debug.Log("Returned value: " + prevlevelscore.ToString());
    SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}

LevelComplete() 中,Debug.Log("Returned value: " + prevlevelscore.ToString());prevlevelscore = result; 之前执行
我想确保在执行Debug.Log 之前更新prevlevelscore 的值。

【问题讨论】:

  • 好吧,因为它不是回调的一部分...如果它应该是延迟代码的一部分,您应该将 Debug.Log("Returned value: " + prevlevelscore.ToString()); 放在回调中...

标签: c# firebase unity3d firebase-realtime-database callback


【解决方案1】:

将其余代码也放入回调中:

public void LevelComplete() 
{
    DatabaseCode.writeDatabase(SceneManager.GetActiveScene().buildIndex + 1, counter);
    DatabaseCode.ReadFromDb(SceneManager.GetActiveScene().buildIndex + 1, (result) => {
        Debug.Log("result " + result.ToString());
        prevscore = result;
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
    });    
}

【讨论】:

    【解决方案2】:

    您的问题是您的 ReadFromDb 方法在完成之前返回。您可以通过将所有代码放入回调中来解决此问题(但您不能一直这样做),或者您可以使用异步等待模式。

    使 ReadFromDb 异步:

        static public async Task ReadFromDb(int level, Action<int> callback) 
        {
            int return_value = -1;
            string sessionId = PlayerPrefs.GetString("SessionID");
    
            await FirebaseDatabase.DefaultInstance.GetReference("users/"+sessionId).GetValueAsync().ContinueWith(task => {
                if (task.IsFaulted) 
                {
                    // Handle the error...
                    Debug.Log("Task faulted");
                    callback(return_value);
                } 
                else if (task.IsCompleted) 
                {
                    DataSnapshot snapshot = task.Result;
                    string score_string = (snapshot.Child(level.ToString()).Value).ToString();
                    Debug.Log("score_string " + score_string);
                    return_value = int.Parse(score_string);
                    callback(return_value);
                }
            });
        }
    

    请注意 GetValueAsync().ContinueWith 之前的 await 键,因为此精确代码是异步的,如果您想在获取结果之前保持代码执行,则需要等待。

    在你的来电者中:

        public async Task LevelComplete() 
        {
            DatabaseCode.writeDatabase(SceneManager.GetActiveScene().buildIndex + 1, counter);
            await DatabaseCode.ReadFromDb(SceneManager.GetActiveScene().buildIndex + 1, (result) => {
                prevlevelscore = result;
                Debug.Log("result " + result.ToString());
            });
            prevscore = prevlevelscore;
            Debug.Log("Returned value: " + prevlevelscore.ToString());
            SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
        }
    

    这个方法也变成异步的(因为异步传播)。同样, await 关键字将一直执行,直到 readFromDb 方法完成。这意味着您的数据将准备就绪。

    【讨论】:

    • 您可能更愿意将 LevelComplete() 设为 public async void .. 否则您应该解释 OP 如何实际调用和使用 public async Task LevelComplete()
    • public async void 是一个任务反模式。检查markheath.net/post/async-antipatterns了解更多信息。
    • 这是有争议的,但实际上是开始调用async 链的唯一方法......你通常不会这样做,因为你永远不知道通话何时结束......在你的情况下无论如何使用回调模式都没关系,因为多亏了回调,您知道呼叫何时结束。如前所述..如果不使用它,请另外解释 OP 应该如何开始调用 async 方法。请参阅链接中的第二部分So it's not necessarily a problem
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-05
    • 1970-01-01
    • 2015-11-01
    • 2017-03-24
    • 1970-01-01
    相关资源
    最近更新 更多