- Home /
How to return value from UnityWebRequest?
I have a script that connects to the database and retrieve data. The GetData function is called by other script. is there a way that I can return the data back to the caller?
public IEnumerator GetData(){
using (UnityWebRequest wwww = UnityWebRequest.Get("http://localhost/BMS/LoadGame.php")) {
yield return wwww.SendWebRequest();
if (wwww.isNetworkError || wwww.isHttpError){
Debug.Log(wwww.error);
} else {
Debug.Log(wwww.downloadHandler.text);
//How to return the result to the caller?
}
}
}
The method that I know is to call another function in other script to pass the data, but this is a lot more troublesome. Is there any direct way that I can return the data to the caller? Thanks!
Answer by Bunny83 · Apr 14, 2019 at 09:25 AM
No, there is no other way. Doing a synchronous http request would block your whole execution until it's done this could take several seconds. Even when it's relatively quick it will mostly take at least around 20ms which would have a huge impact on your framerate.
The only alternative is to do whatever you want to do on a seperate thread. However as you may know you can't use most of the Unity API from other threads. Also doing synchronous web requests or using threads may not be supported at all depending on your target platform. (WebGL for example).
So the only reasonable way is to use a callback. When you use your method inside another coroutine you can actually wait for your coroutine and it's almost like a synchronous call. For example:
public IEnumerator GetData(System.Action<string> aOnData)
{
// [ ... ]
if (aOnData != null)
aOnData(wwww.downloadHandler.text);
}
When using this inside another coroutine you can do:
IEnumerator DoStuff()
{
// [ ...]
string data = "";
yield return StartCoroutine(GetData(s=>data = s));
// use "data" here
}
Of course in order to wait for another coroutine to finish you have to call it from within a coroutine. Always keep in mind that almost the whole scripting environment of Unity runs on the main thread. Actually blocking the thread would block your whole application.
@Bunny83 This one works for me. Appreciated! Never heard of Action before though. But this one is also quite easy to use. Since I am only connecting to localhost, so the callback function responses quite fast.
System.Action
(as well as all the generic versions System.Action<T>
) is just a predefined delegate type. System.Action literally is defined just as
public delegate void Action();
So a delegate (function pointer) to a method that takes no parameters and doesn't return a value. The System.Action<T>
delegate is defined as
public delegate void Action<T>(T p1);
so "T" is essentially a place holder for an actual type.
Besides the Action delegate types there are also "Func" delegates which serve the same purpose but also define a return type. The last generic parameter is the return type. So System.Func<int, Vector3, string>
would be compatible to a method that looks like this:
string Some$$anonymous$$ethod(int aInt, Vector3 aVec)
{
return "int: " + aInt + " vec: " + aVec;
}
Beside actual named methods you can also assign / pass anonymous methods to delegates. Anonymous methods are just like normal methods but they don't have a symbolic name. They are declared within another code block, see$$anonymous$$gly "on the fly". Anonymous methods basically come in two flavors: Simple static methods and closures. Whenever the body of the anonymous method references a variable or instance methods from another scope it becomes a closure. A closure can actually "capture" variables from the outer scope. This is what we used here. This is a so called lambda expression s=>data = s
. This would be equivalent to a method that looks somethine like this:
void AssignData(string s)
{
data = s;
}
For more information see the lambda expression documentation
Hello, sorry for the late bump but I'm actually encountering the exact same problem. Here is my code:
IEnumerator SetRecipeList(WWWForm form, System.Action<string> callback = null)
{
using (UnityWebRequest www = UnityWebRequest.Post($"{rootURL}get_recipe_list.php", form))
{
yield return www.SendWebRequest();
callback.Invoke(www.downloadHandler.text);
}
}
And here is my main function that I would love if it could return the string:
string GetRecipeList(string search)
{
WWWForm form = new WWWForm();
form.AddField("searchText", search);
string result;
StartCoroutine(SetRecipeList(form, returnValue => result = returnValue));
return result;
}
I don't understand how I can get the result to be actually returned (this function is not in the IEnumerator as I want to use it in other files/functions). I tried the callback answer, as can be seen, but the 'return result' line is always executed before... I would greatly appreciate some help :D
Your answer
Follow this Question
Related Questions
Super slow network speed in editor with some routers 0 Answers
$_FILES is empty when I send a file from WWWForm 2 Answers
How to stream audio before completely downloaded? 0 Answers
Get Contents of Folder Using UnityWebRequest 0 Answers
How to get UnityWebRequest data early when using php flush() 1 Answer