【问题标题】:why this in a callback causes the code to stop?为什么回调中的 this 会导致代码停止?
【发布时间】:2021-01-30 00:19:23
【问题描述】:

在使用 GetValueAsync().ContinueWith(task..) 中的回调通过 Firebase 恢复我的数据后,我想实例化我的预制件以查看我的排行榜的分数列表。但是,它什么也没做,我也没有错误。只要遇到“this”或“instantiate”,代码就会在回调 UseSores 中停止。

public class Leaderboardmanager : MonoBehaviour
{

    public GameObject rowLeardBoard;
    FirebaseDB_Read read;
    float positionX; 
    int nbRows = 10;

    void Start()
    {   
        read = (gameObject.AddComponent<FirebaseDB_Read>());
        GetScorePlayer();
    } 

    void GetScorePlayer()
    {
        read.GetScores(UseScores, "entries/LeaderBoard/", nbRows);
    }

    void UseScores(IList<FirebaseDB_Read.Score> scores)
    {
        Debug.Log("arrive here");
        positionX = this.transform.position.y; 
        Debug.Log("does not arrive here");
    }
}

这是获取我的数据:

public class FirebaseDB_Read : MonoBehaviour
{

    public class Score
    {
        public string UID;
        public string score;
        public int rank;
    }


    public void GetScores(Action<IList<Score>> callback, string URL_TO_SCORES, int limit)
    {
        DatabaseReference scoresRef = FirebaseDatabase.DefaultInstance.GetReference(URL_TO_SCORES);

        scoresRef.OrderByChild("score").LimitToLast(limit).GetValueAsync().ContinueWith(task =>
        {
            DataSnapshot snapshot = task.Result;
            IList<Score> objectsList = new List<Score> { };

            int i = 1;
            foreach (var childSnapshot in snapshot.Children)
            {
                Score score = new Score();
                score.rank = i;
                score.UID = childSnapshot.Child("UID").GetValue(true).ToString();
                score.score = childSnapshot.Child("score").GetValue(true).ToString();

                objectsList.Add(score);
                i++;
            }

            callback(objectsList);
        });
    }
}

【问题讨论】:

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


    【解决方案1】:

    这是 Unity 中经常被问到的问题:因为你 ContinueWith后台线程上!

    Unity 不是线程安全的,这意味着大多数 Unity API 只能在 Unity 主线程中使用。

    Firebase 专门为 Unity 提供了一个扩展:ContinueWithOnMainThread,它确保在访问 API 有效的 Unity 主线程中处理结果。

    scoresRef.OrderByChild("score").LimitToLast(limit).GetValueAsync().ContinueWithOnMainThread(task =>
    {
        ...
    });
    

    作为替代方案,您可以使用一种所谓的“主线程调度程序”模式,并确保callback 在接收方的主线程中执行。这样做的好处是您列表中仍然昂贵的操作都在后台线程上执行,不会影响 UI 性能

    scoresRef.OrderByChild("score").LimitToLast(limit).GetValueAsync().ContinueWith(task =>
    {
        ...
    });
    

    但随后在FirebaseDB_Read的接收方

    private readonly ConcurrentQueue<Action> _mainThreadActions = new ConcurrentQueue<Action>();
    
    private void Update()
    {
        if(_mainThreadAction.Count > 0)
        {
            while(_mainThreadActions.TryDequeue(out var action))
            {
                action?.Invoke();
            }
        }
    }
    
    void GetScorePlayer()
    {
        read.GetScores(UseScores, "entries/LeaderBoard/", nbRows);
    }
    
    void UseScores(IList<FirebaseDB_Read.Score> scores)
    {
        // handle this in the next main thread update
        _mainThreadActions.Enqueue(() =>
        {
            Debug.Log("arrive here");
            positionX = this.transform.position.y; 
            Debug.Log("does not arrive here");
        }
    }
    

    这当然会在检查Update 中的任何新操作时带来一点开销。因此,如果您计划使用多个此类后台操作,请确保在一个中心位置实施它们,以限制开销;)

    【讨论】:

    • @Vanz 很高兴为您提供帮助!请随时接受答案;)
    猜你喜欢
    • 1970-01-01
    • 2018-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多