- Home /
How can I check if async function is finished?
Hi,
I have read other posts about the same problem but they are not exactly same with my problem. I have created the bool flag to control if the asynchronous function is finished or not. Below snippet is what I am doing right now but the problem is because of while loop Unity freezes as if it never escape while loop but it should break while loop since waitFlag changes in the "getAllElementsAsync" method. Without while loop "getAllElements" method returns the value as null since it returns value before it is changed by "getAllElementsAsync" method. I am open to any other solutions that can solve my problem which is returning value after async method finishes. I have also tried creating coroutine for getAllElementsAsync method but it still returns value before coroutine finishes.
public class DatabaseConnection : MonoBehaviour {
private DataSnapshot dataSnapshot;
private bool waitFlag = true;
public Datasnapshot getAllElements(){
getAllElementsAsync();
while(this.waitFlag){}
return this.dataSnapshot
}
public void getAllElementsAsync(){
FirebaseApp.DefaultInstance.SetEditorDatabaseUrl("someURL");
DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference;
reference.GetValueAsync().ContinueWith(task => {
if (task.IsFaulted)
{
Debug.Log("not ok");
}
else if (task.IsCompleted)
{
Debug.Log("ok");
this.dataSnapshot = task.Result;
this.waitFlag = false;
}
});
}
}
What didn't you understand during the discussion we had here together? You can't make an asynchronous function to return directly a value in a synchronous function....
Answer by TsvetanTsankov · Aug 01, 2018 at 10:22 AM
Use a Coroutine instead of a void -> https://docs.unity3d.com/ScriptReference/MonoBehaviour.StartCoroutine.html
Correct me if I am wrong but Startcoroutine is also async function. I also tried that as I said in the question but it didn't help.
public IEnumerator getAllElementsAsync () {
FirebaseApp.DefaultInstance.SetEditorDatabaseUrl ("someURL");
DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference;
reference.GetValueAsync ().ContinueWith (task => {
if (task.IsCompleted) {
Debug.Log ("Success!");
this.dataSnapshot = task.Result;
this.waitFlag = false;
} else (task.IsFaulted) {
Debug.Log ("Task is Faulted --> WAITING");
yield return null;
}
});
}
This won't work and won't compile. Because getAllElementsAsync
returns an IEnumerator
but you don't yield anything in it, and the lambda function in the ContinueWith
returns void
but you try to yield something. The best you can do is:
public IEnumerator getAllElementsAsync () {
bool valueReturned = false ;
FirebaseApp.DefaultInstance.SetEditorDatabaseUrl ("someURL");
DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference;
reference.GetValueAsync ().ContinueWith (task => {
if (task.IsCompleted) {
Debug.Log ("Success!");
this.dataSnapshot = task.Result;
} else (task.IsFaulted) {
Debug.Log ("Task is Faulted --> WAITING");
}
valueReturned = true ;
});
while( !valueReturned )
{
yield return null ;
}
}
But while this works, it does not answer the impossible request of @mercem.
Answer by TsvetanTsankov · Aug 01, 2018 at 02:07 PM
You provide the function you want to be called back when the data is successfully loaded...
using System.Collections;
using System.Collections.Generic;
using Firebase.Database;
using UnityEngine;
public class CallBackCoroutine : MonoBehaviour {
private bool waitFlag = false;
public void GetAll (System.Action<DataSnapshot> callBack) {
if (waitFlag == false) { // IF it has already started getting the data -> Dont try to retrieve it again
waitFlag = true;
StartCoroutine (getAllElementsAsync (callBack));
}
}
private IEnumerator getAllElementsAsync (System.Action<DataSnapshot> callBack) {
DataSnapshot dataSnapshot = null;
// FirebaseApp.DefaultInstance.SetEditorDatabaseUrl ("someURL");
DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference;
reference.GetValueAsync ().ContinueWith (task => {
if (task.IsCompleted)
dataSnapshot = task.Result;
else
Debug.Log ("Task is Faulted --> WAITING");
});
yield return new WaitUntil (() => { return dataSnapshot != null; });
waitFlag = false;
callBack (dataSnapshot);
}
}
The problem is that mercem does not want to have a callback function, he / she wants the value to be returned synchronously. I tried to explain it was not possible here, but he / she does not seem to understand this is not possible.
By the way, using a coroutine here is not necessary, you just need to call the callback in the lambda expression provided in the ContinueWith
function
Yes, you are totally correct and you've provided the example in the other "Question".
Thanks for letting me know about this peculiar case... It's even a different account xD
It is different account because he is my friend we work on same project. Hence we have same problem. None of us was able to solve problem. He tried callback function but as he said in that question you cannot return value inside a lambda function. Now I am trying to achieve solution with this approach but I coudn't find any.
Answer by mercem · Aug 01, 2018 at 01:01 PM
I know coroutine is not async but I say startcoroutine is async. I tried to write getAllElements as coroutine then I called it with startcoroutine but it still returns value before coroutine finishes. I need to use this method from outside of this code so it needa to return value. Is there a way to return value from coroutine and assing it to parameter, like “var constant_value = startcoroutine(getallelements());”
How is your coroutine returning a value that you are using?
Can you share me the link to this quote
StartCoroutine is async
Answer by hqarts · Aug 01, 2018 at 11:00 AM
Coroutine is not async function:
.1. Coroutine is a request to a IEnumerator to get just an element of it at every frame:
.2. Coroutine can start at any frame and can cancel at any frame too.
.3. Coroutine can be finish by itself.
private IEnumerator SomeCoroutine()
{
// (1)
while (condition)
{
// (2)
print(Time.frameCount);
yield return null;
}
// (3)
}
(1) : code on this section will invoke just once at the first frame that coroutine called.
(2) : code on this section will executed per frame while condition is true. (you can think this section as code that you write on Update() method)
(3) : code on this section will call once when condition is false. at this state corotine stoped by itself (by ending the loop)
Note: if you stop the coroutine before the condition section (3) will not reach at all.
Note: section (2) called just per frame and you don't break the main threat cause of infinite loop.
Your answer

Follow this Question
Related Questions
Play(offsetInSamples) acuracy - still cannot get it to work perfectly 5 Answers
Photon Unity Networking (Viking Demo) Error: Argument is out of range. 1 Answer
How do I keep values synchronized over the Photon Network? 1 Answer
Sending texture updates from client to server 1 Answer
Best way to synchronize projectile transform in networked game? 1 Answer