问题
I am trying to receive the JSON value from the Realtime Database of Firebase using Unity.
I do the following:
FirebaseDatabase.DefaultInstance
.GetReference("Leaders").OrderByChild("score").GetValueAsync().ContinueWith(task =>
{
if (task.IsFaulted)
{
Debug.LogError("error in reading LeaderBoard");
return;
}
else if (task.IsCompleted)
{
Debug.Log("Received values for Leaders.");
string JsonLeaderBaord = task.Result.GetRawJsonValue();
callback(JsonLeaderBaord);
}
}
});
Trying to Read the CallBack :
private string GetStoredHighScores()
{
private string JsonLeaderBoardResult;
DataBaseModel.Instance.RetriveLeaderBoard(result =>
{
JsonLeaderBoardResult = result; //gets the data
});
return JsonLeaderBoardResult; //returns Null since it doesn't wait for the result to come.
}
Question is how do i wait for the callback to return the value and afterwards return
the value of the JsonLeaderBoardResult
.
回答1:
return JsonLeaderBoardResult;
//returns Null since it doesn't wait for the result to come.
The RetriveLeaderBoard
function doesn't return immediately. You can either use coroutine to wait for it or return the JsonLeaderBoardResult
result via Action
. Using Action
make more sense in your case.
Change the string return type to void then return the result through Action
:
private void GetStoredHighScores(Action<string> callback)
{
string JsonLeaderBoardResult;
DataBaseModel.Instance.RetriveLeaderBoard(result =>
{
JsonLeaderBoardResult = result; //gets the data
if (callback != null)
callback(JsonLeaderBoardResult);
});
}
Usage:
GetStoredHighScores((result) =>
{
Debug.Log(result);
});
EDIT:
That is great, but still need to do some stuff after getting the result in `GetStoredHighScores' outside the Action, otherwise i can get an error like: get_transform can only be called from the main thread.
You get this error because RetriveLeaderBoard
is running from on another Thread. Grab UnityThread
from this post then do the callback on the main Thread with UnityThread.executeInUpdate
.
Your new code:
void Awake()
{
UnityThread.initUnityThread();
}
private void GetStoredHighScores(Action<string> callback)
{
string JsonLeaderBoardResult;
DataBaseModel.Instance.RetriveLeaderBoard(result =>
{
JsonLeaderBoardResult = result; //gets the data
UnityThread.executeInUpdate(() =>
{
if (callback != null)
callback(JsonLeaderBoardResult);
});
});
}
回答2:
You're seeing a classical confusion with asynchronous APIs. Since loading data from Firebase may take some time, it happens asynchronously (on a separate thread). This allows your main code to continue, while the Firebase client is waiting for a response from the server. When the data is available, the Firebase client calls your callback method with that data, so that you can process it.
It's easiest to see what this does in your code by placing a few logging statements:
Debug.Log("Before starting to load data");
FirebaseDatabase.DefaultInstance
.GetReference("Leaders").OrderByChild("score").GetValueAsync().ContinueWith(task => {
Debug.Log("Got data");
}
});
Debug.Log("After starting to load data");
When you run this code, it prints:
Before starting to load data
After starting to load data
Got data
This is probably not the order in which you expected the output. Due to the asynchronous nature of the call to Firebase, the second log line gets printed last. That explains precisely why you're seeing an empty array when you return it: by that time the data hasn't been loaded from Firebase yet, and your ContinueWith
hasn't executed yet.
The solution to this is always the same: since you can't return data that hasn't loaded yet, you have to implement a callback function. The code you shared does that twice already: once for the ContinueWith
of Firebase itself and one in RetriveLeaderBoard
.
Any code that needs to have the up to date leaderboard, will essentially have to call RetriveLeaderBoard
and do any work with the leaderboard data in its callback. For example, if you want to print the leaderboard:
DataBaseModel.Instance.RetriveLeaderBoard(result => {
Debug.Log(result);
});
来源:https://stackoverflow.com/questions/53335689/retrieve-data-from-realtime-database-with-action-callback