为什么回调中的这个会导致代码停止?
why this in a callback causes the code to stop?
在使用 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);
});
}
}
这是 Unity 中的一个常见问题:因为您 ContinueWith
在 后台线程上 !
Unity 不是 thread-safe,这意味着大多数 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
中的任何新操作。因此,如果您打算使用多个此类后台操作,请确保在一个中心位置实施它们,以限制开销;)
在使用 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);
});
}
}
这是 Unity 中的一个常见问题:因为您 ContinueWith
在 后台线程上 !
Unity 不是 thread-safe,这意味着大多数 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
中的任何新操作。因此,如果您打算使用多个此类后台操作,请确保在一个中心位置实施它们,以限制开销;)