我正在为服务器端完全基于Firebase的游戏编写代码。我希望在游戏中使用Auth,数据库,InstanceID,消息传递和云函数。 作为C#的新手,我第一次在Firebase中遇到了C#“任务”。 我将使用数据库很多次(例如“分数更新”,“好友请求”,“聊天”,“朋友做到了”,“朋友做到了”)。 我通常对Singleton Pattern(GameManager,EnemyManager,SoundManager等)感到满意。 但是使用Firebase,因为它的大多数调用是异步的,并且是通过Tasks实现的。我认为我需要采取不同的解决方法来实施Manager。
例如,我需要向特定朋友发送“朋友请求”。 UIManager是处理UI事件等的脚本。我想从此脚本调用Method到另一个Manager(例如,FriendsManager)。但是我需要首先检查这个朋友是否已经是数据库的我的朋友?所以,我要做的是
class UIManager
{
void OnFriendRequestClicked(string friendId)
{
bool userExists = FriendsManager.instance.UserExists(friendId);
if(userExists)
// Proceed with Sending Request
FriendsManager.instance.SendRequest(friendId);
else
// Show a Dialogue that User ID is invalid
ShowError("User Id is invalid");
// NOTE: The above code block of "condition" is executed before
// the UserID is validated from FriendsManager
// I know its because of Task. But how can I alter this code
// to do something in the similar pattern?
}
}
class FriendsManager
{
bool UserExists(string userIdToCheck)
{
reference.Child("users").Child(userIdToCheck).GetValueAsync().ContinueWith(
task=>
{
if(task.IsCompleted)
{
if(task.Result == null)
return false; // (expected) Return false to Method "UserExists"
else
return true; //(expected) Return true to Method "UserExists"
// But this won't actually return "bool" to the method,
// it actually returns to its own "Task"
//NOTE: -> How to Return from here to the Method?
)};
}
答案 0 :(得分:1)
从Firebase异步加载数据。该应用程序继续运行,而不是在加载数据时等待/阻止。然后,当数据可用时,它将调用您的回调。
通过一些日志记录语句,您可以最轻松地看到这一点:
Debug.Log("Before starting to load data");
reference.Child("users").Child(userIdToCheck).GetValueAsync().ContinueWith(task=> {
Debug.Log("Data loaded");
});
Debug.Log("After starting to load data");
运行此代码时,它将记录:
开始加载数据之前
开始加载数据后
已加载数据
这可能不是您所期望的,但是可以完美解释为什么您不能从回调中返回值:UserExists
到此为止已经结束。
这意味着任何需要访问数据库中数据的代码都必须在ContinueWith
块内 (或从那里调用)。
最简单的方法是将代码从您的OnFriendRequestClicked
移至UserExists
:
bool UserExists(string userIdToCheck) {
reference.Child("users").Child(userIdToCheck).GetValueAsync().ContinueWith(task=>
{
if(task.IsCompleted)
{
if(task.Result == null)
ShowError("User Id is invalid");
else
FriendsManager.instance.SendRequest(friendId);
)};
}
然后可以在不带if
的情况下调用此函数。
上述方法效果很好,但意味着您的UserExists
方法在不同情况下不再可重用。要使其可重复使用,可以将自己的回调接口传递到UserExists
中。
例如,使用Task
:
bool UserExists(string userIdToCheck, Action<bool> callback) {
reference.Child("users").Child(userIdToCheck).GetValueAsync().ContinueWith(task=>
{
if(task.IsCompleted)
{
if(task.Result == null)
callback(false);
else
callback(true);
)};
}
然后调用它:
FriendsManager.instance.UserExists(friendId, userExists => {
if(userExists)
FriendsManager.instance.SendRequest(friendId);
else
ShowError("User Id is invalid");
})