rogdop
rogdop

Reputation: 30

How to read value from firebase in Unity?

I can't really understand how to read any values from firebase. In google documentation it is said that I need to use GetValueAsync().ContinueWith(), but it works rather weird. So, if I use:

FirebaseDatabase.DefaultInstance.GetReference("Leaders").GetValueAsync().ContinueWith(task => {
    if (task.IsFaulted) {
      Debug.Log("error");
    }
    else if (task.IsCompleted) {
      DataSnapshot snapshot = task.Result;
      Debug.Log(snapshot.Value.ToString());
    }
  });

then it prints true value and all is ok. But if i'm trying to find a GameObject with this name, nothing happens.

else if (task.IsCompleted) {
  DataSnapshot snapshot = task.Result;
  Debug.Log(GameObject.Find(snapshot.Value.ToString()).name);
} 

it doesn't print anything. It stoppes on this line, but without any errors or messages. And this problem happens every time I try to do smth with snapshot. A very simple thing, but i can't imagine what can be wrong?? Please help.

Upvotes: 1

Views: 1392

Answers (1)

Patrick Martin
Patrick Martin

Reputation: 3131

I wrote an article and recorded a video on handling multitasking in Unity, and you should definitely check those out if you curious about all your options.

For your issue specifically, I'd suggest simply changing ContinueWith to ContinueWithOnMainThread. This is a drop in replacement.

FirebaseDatabase.DefaultInstance.GetReference("Leaders").GetValueAsync().ContinueWithOnMainThread(task => {
    if (task.IsFaulted) {
      Debug.Log("error");
    }
    else if (task.IsCompleted) {
      DataSnapshot snapshot = task.Result;
      Debug.Log(snapshot.Value.ToString());
    }
  });

Which brings me to the explanation of what's happening:

Something that's tricky about Firebase and Unity is that Firebase tends to perform work on a background thread to avoid blocking your game for long running network operations. Unlike APIs like Unity's UnityWebRequest, it's left to developers to work out how and when to move logic back into the game thread. This means that if you wanted to do more work in the background with the result of this operation you could, but it also means that you risk very unexpected behaviour if you start to do non-thread-safe operations in the continuation.

Unity protects some functions, such as GameObject.Find, from access in a background thread -- Often raising an exception when it detects something untoward. ContinueWith will start executing wherever the long running task finished, whereas ContinueWithOnMainThread will push your continuation logic into a queue that gets executed on the main thread. This is generally efficient and will make sure that any Unity logic you execute in your continuation occurs at an expected time.

You may opt to convert a task into a coroutine by writing:

var task = FirebaseDatabase.DefaultInstance.GetReference("Leaders").GetValueAsync();
yield return new WaitUntil(()=>task.IsComplete);
if (task.Exception) {
    // something bad happened, handle it
    yield break;
}
var snapshot = task.Result;

Which would give you even more control over where your logic executes in your game and provides a bit more memory safety. You could also use async/await to make the code look a little more like typical C#.

Upvotes: 1

Related Questions