从 Firebase 中的实时数据库获取数据后,无法写入 Unity 的 TMPro 文本字段

Posted

技术标签:

【中文标题】从 Firebase 中的实时数据库获取数据后,无法写入 Unity 的 TMPro 文本字段【英文标题】:Cannot write to Unity's TMPro text field after getting data from Realtime Database in Firebase 【发布时间】:2020-12-28 11:33:25 【问题描述】:

我正在尝试从 Firebase 中的实时数据库中提取数据,然后将该字符串统一放入 TMP_Text 字段中。

在我的代码的 .ContinueWith(task => 部分中写入文本字段似乎存在问题。在 task.isCompleted 中,我可以在将其转换为字符串后获取快照打印值,但是,一旦我尝试写入文本字段,代码就会拖拽。在下面的示例中,输出如下。

    打印快照,包括键和值 将快照的值打印为字符串 没有错误没有任何事情发生 Value 的第 4 次打印根本不打印
public void PopulateScoreBoard()
    
        FirebaseDatabase.DefaultInstance.GetReference("userlist").Child(LoadingScreen.userID).Child("score").GetValueAsync().ContinueWith(task =>
        
            if (task.IsFaulted)
            
                //handle error
                scoreboard.text = "Error!";
            
            else if (task.IsCompleted)
            
                //get snapshot fo data
                DataSnapshot snapshot = task.Result;
                print(snapshot);
                print(snapshot.Value.ToString());

                //Get the scoreboard value within the result snapshot
                scoreboard.text = snapshot.Value.ToString();

                //print the same value to ensure it is working
                print(snapshot.Value.ToString());
            
        );
    

期待获得一些意见,我假设有某种原因您无法在其中写入任何内容,但是,我找不到它。如果是这种情况,我的替代方案是什么?

*更新:似乎在进一步测试之后,您无法在 ContinueWith(task => 中设置任何内容,这正常吗?

【问题讨论】:

【参考方案1】:

我能够找到答案,但我仍然希望得到一些意见,看看我是否做得对。

我改成了这段代码,它似乎工作正常。

public void loadData()
    
        FirebaseDatabase.DefaultInstance.GetReference("userlist").ValueChanged += Script_ValueChanged;
    

    private void Script_ValueChanged(object sender, ValueChangedEventArgs e)
    
        scoreboard.text = e.Snapshot.Child(LoadingScreen.userID).Child("userScore").GetValue(true).ToString();
    

然后在开始时调用它。

【讨论】:

【参考方案2】:

首先,我认为您可以通过将 ContinueWith 替换为 ContinueWithOnMainThread 来解决最初的问题:

public void PopulateScoreBoard()
    
        FirebaseDatabase.DefaultInstance.GetReference("userlist").Child(LoadingScreen.userID).Child("score").GetValueAsync().ContinueWithOnMainThread(task =>
        
            if (task.IsFaulted)
            
                //handle error
                scoreboard.text = "Error!";
            
            else if (task.IsCompleted)
            
                //get snapshot fo data
                DataSnapshot snapshot = task.Result;
                print(snapshot);
                print(snapshot.Value.ToString());

                //Get the scoreboard value within the result snapshot
                scoreboard.text = snapshot.Value.ToString();

                //print the same value to ensure it is working
                print(snapshot.Value.ToString());
            
        );
    

原因是ContinueWith 会在后台返回。然后执行非线程安全操作scoreboard.text = "Error!";,这将导致崩溃异常范围内的某些事情。我写过一篇关于这个here的文章。

现在,您的答案更多正确。 GetDataAsync 将注册一个 ValueChanged 侦听器,等待结果,然后取消注册此侦听器。问题在于,这意味着如果您的缓存中有过时数据,您的 GetValueAsync 将是从 Firebase 后端检索到的最后一个值,而不是最新数据。

查看您的代码,您应该做的唯一不同的事情是缓存 "userlist" 引用并稍后取消注册。这与 Unity 如何处理内存和对象生命周期有关 - 在您的代码中可以将文本设置在空对象上:

private DatabaseReference _userListReference;

void Start() 
    _userListReference = FirebaseDatabase.DefaultInstance.GetReference("userlist");
    _userListReference.ValueChanged += Script_ValueChanged;


void OnDestroy() 
    _userListReference.ValueChanged -= Script_ValueChanged;


private void Script_ValueChanged(object sender, ValueChangedEventArgs e)

    scoreboard.text = e.Snapshot.Child(LoadingScreen.userID).Child("userScore").GetValue(true).ToString();

由于current bug,您必须缓存引用以删除事件侦听器。如果您尝试使用 GetReference 再次检索它,您将创建底层对象的第二个 C# 副本,并且事件侦听器将继续存在。

【讨论】:

以上是关于从 Firebase 中的实时数据库获取数据后,无法写入 Unity 的 TMPro 文本字段的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Flutter 中的 Firebase 实时数据库中按 categoryId 获取产品?

如何从 Firebase 实时数据库中获取数据到 Flutter 中的列表中?

如何从 Firebase 中的实时数据库中获取数组

如何根据 Angular 6 中的 Firebase 实时数据库中的键获取单个记录

从 Flutter 应用程序中的 Firebase 实时数据库事件获取父节点

获取firebase实时数据库中的随机条目