简体   繁体   中英

How would i make a function that returns data

Ive tried to do it but some of the code runs Asynchronously causing problems, also you cant return a value inside GetReference. I cant use Coroutines they dont return values. This is how far ive gotten.

public string getData(string DataName)
{

    string returnDataValue = null;

    FirebaseDatabase dbInstance = FirebaseDatabase.DefaultInstance;

    dbInstance.GetReference("users").Child(User.UserId).GetValueAsync().ContinueWith(task => 
    {
    if (task.IsCompleted) 
        {
            DataSnapshot snapshot = task.Result;

            returnDataValue = snapshot.Child(DataName).Value.ToString();

        }
    });

    print(returnDataValue);
    return returnDataValue;
}

Your method is internally using an async Task<T> .

There are basically three options:

option 1 (don't)

Convert the call to a synchronous one and thereby freeze your method until the result comes back.

public string getData(string DataName)
{
    FirebaseDatabase dbInstance = FirebaseDatabase.DefaultInstance;

    var snapshot = dbInstance.GetReference("users").Child(User.UserId).GetValueAsync().Result;    

    var returnDataValue = snapshot.Child(DataName).Value.ToString();

    print(returnDataValue);
    return returnDataValue;
}

I hope I don't have to explain why this is a bad idea;)

Anyway: It will freeze your entire Unity application, until the task is finished. Definitely not what you would want to do!

option 2 (don't)

Make your method await the result so it can return it.

public async Task<string> getData(string DataName)
{
    FirebaseDatabase dbInstance = FirebaseDatabase.DefaultInstance;

    var snapshot = await dbInstance.GetReference("users").Child(User.UserId).GetValueAsync();

    var returnDataValue = snapshot.Child(DataName).Value.ToString();

    print(returnDataValue);
    return returnDataValue;
}

The issue with that is

  • You only moved the problem one level Up since now whatever method is calling this has to also wait until the results are back
  • I don't know if it even compiles since I don't know Firebase and am only on the phone:D

option 3

Instead use a callback.

For Unity specific you should not use ContinueWith but rather ContinueWithOnMainThread which makes sure the callback is executed in the Unity main thread where you can safely use the Unity API

public void getData(string DataName, Action<string> onSuccess)
{
    FirebaseDatabase dbInstance = FirebaseDatabase.DefaultInstance;

    dbInstance.GetReference("users").Child(User.UserId).GetValueAsync().ContinueWithOnMainThread(task => 
    {
        if (task.IsCompleted) 
        {
            DataSnapshot snapshot = task.Result;

            returnDataValue = snapshot.Child(DataName).Value.ToString();

            print(returnDataValue);
            onSuccess?.Invoke(returnDataValue);
        }
    });
}

So instead of doing something like

var result = getData("someName");
// Do something with result

You would rather pass in a callback action either as a method like

getData("someName", OnSomeDataReceived);

...

private void OnSomeDataReceived (string result)
{
    // Do something with result
}

or the same as a Linda expression

getData("someName", result =>
{
    // Do something with result
});

If you're ok with using async/await in your code base, you can do this:

public async Task<string> getData(string DataName)
{
    FirebaseDatabase dbInstance = FirebaseDatabase.DefaultInstance;
    var snapshot = await dbInstance.GetReference("users").Child(User.UserId).GetValueAsync();
    
    // feel free to do additional error checking here first.
    return snapshot.Child(DataName).Value.ToString();
    print(returnDataValue);
}

There are a number of caveats including:

  1. This returns on your calling thread. So if you call await getData(); on a background thread it will return in your background thread.
  2. Unity makes no guarantee where in your game loop this returns. In my testing, it appears to come in roughly when Coroutines would execute - but you might want to be a little careful accordingly.
  3. This is probably not doing what you think it is . To elaborate a little, GetValueAsync registers a ValueChanged listener, waits for it to be called once, then unregisters this listener. If persistence is turned off (this will slow down your game) or this is the first time you retrieve the data, this will likely do what you expect. If persistence is turned on and this data is in the cache, you will get the cached value in GetValueAsync and the cache will be updated as part of registering the ValueChanged listener (but you won't get notified since it's been unregistered). When possible, express your code using the ValueChanged callback in Realtime Database.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM