Home > Net >  Unity Async or Coroutine WebRequest and wait on data
Unity Async or Coroutine WebRequest and wait on data

Time:08-07

The Idea is, that my Data get loaded, asynchron, when my app startet. Because the user normaly need some seconds to interact and in this time, i should get my data. (For understanding reasons, it will be a book app, with some books)

To do this, in loadingprofile i open a method on a static class to start loading. In the Screen where i want to show my data, i check with a method on the static class, if the data are there ( and wait if theire not).

So in the Profil loading screen i did this:

public class LoadProfiles : MonoBehaviour
{
    private void Awake()
    {
        if (!LoadingData.dataLoaded)
        {
            LoadingData.LoadData();
        }
    }
    void Start()
    {
        //Loading Profile Dataa
    }
}

Then when the User click on a profile, i open the next scene "Bookshelf" and a game object in it has the following script attachted to read the data (the book categories). so i open the wait on data method, that shoud return, when the data are arrived.

public class PopulateShelf : MonoBehaviour
{
    private void Start()
    {
        LoadingData.WaitOnData();
        LoadingData.Categories.ForEach(c => {
            //create categories
        });
    }
}

The static loading class looks like the following

public class LoadingData : MonoBehaviour
{
    public static List<CategoryDTO> Categories;
    public static IEnumerator CategoriesRequest;
    public static bool dataLoaded = false;

    public static void LoadData()
    {
        CategoriesRequest = LoadCategories();
        dataLoaded = true;
    }
    public static void WaitOnData()
    {
        if (!dataLoaded) LoadData(); 
        while (CategoriesRequest.MoveNext())
        {
            //Log wait on categories
        }
    }
    public static IEnumerator LoadCategories()
    {
        UnityWebRequest request = UnityWebRequest.Get(Constants.apiURL   Constants.apiURLCategories);
        yield return request.SendWebRequest();

        while (!request.isDone)
        {
            yield return true;
        }

        if (request.result == UnityWebRequest.Result.ConnectionError)
        {
            //Log error
        }
        else
        {
            Categories = JsonConvert.DeserializeObject<List<CategoryDTO>>(request.downloadHandler.text);
            Categories.Sort((x, y) => x.Order.CompareTo(y.Order));
        }
    }
}

So, the problem is that the on the loging screen, it opens the LoadingData.LoadData Method (but it do not start loading).

When im in the Bookshelf Scene, and open LoadingData.WaitOnData it starts loading the data and the User have to wait.

I also tried it with StartCoroutines. I refactored the LoadingData class, to a non static class. Startet the Coroutings in the LoadData Method.

First it looked like it worked, the data was loaded in the profileScene

Because of it was not static, i had to pass somehow the Object. To do this i created in a static script a Constants for a static LoadingData script variable.

In the Profile Scene i attached it and loaded the data. When i wanted to read it in the BookShefScene, i got a null refrence in my static class... Here would be the class with coroutines

public class LoadingData : MonoBehaviour
{
    public Dictionary<int, BookDTO> Books = new Dictionary<int, BookDTO>();
    public List<CategoryDTO> Categories;
    public bool dataLoaded = false;

    public void LoadData()
    {
        StartCoroutine(LoadCategories());
        StartCoroutine(LoadBooks());
        dataLoaded = true;
    }
    public void WaitOnData()
    {
        if (!dataLoaded) LoadData();
        while (categorieLoaded)
        {
           //log waiting
        }
    }
    public IEnumerator LoadCategories()
    {
        UnityWebRequest request = UnityWebRequest.Get(Constants.apiURL   Constants.apiURLCategories);
        yield return request.SendWebRequest();

        while (!request.isDone)
        {
            yield return true;
        }

        if (request.result == UnityWebRequest.Result.ConnectionError)
        {
            //Log Error
            
        }
        else
        {
            Categories = JsonConvert.DeserializeObject<List<CategoryDTO>>(request.downloadHandler.text);
            Categories.Sort((x, y) => x.Order.CompareTo(y.Order));
        }
    }
}

in profile loading screen, to attache my script to the static variable, i said something like this:

Constants.loadingData = this.GetComponent<LoadingData>();
Constants.loadingData.LoadData();

and in the bookshelf i said

Constants.loadingData.WaitOnData();
Constants.loadingData.Categories();

I checked with the Debuger, in the Profile Scene the Constants.loadingData was created and referenced. In the Bookshelf Scene, i dont saw the referenced object (it was null)...

can anyoune help me with one of this solution? or have a third solution?

CodePudding user response:

I think your condition should be

if(!dataLoaded) LoadData();

Same for the categorieLoaded, maybe the name is misleading and you are using them correctly (?)

Is the GameObject stored in Constants.loadedData set as dontDestroyOnLoad? Maybe when you change scene it gets destroied and set to null.

Also I would suggest to have a better way of waiting for the data to load, if it takes seconds the user will not be able to interract with the game since the while loop will freeze the entire window, you can make your own method that checks every frame if the data got loaded.

private IEnumerable WaitForData() 
{
   while(!Constants.loadedData.Loaded) return null;
   // populate the bookshelf
   // foreach(Book book in Constants.Books)
}

You need to call LoadData() somewhere before calling this, you could setup a loading screen while waiting aswell to make players understand.

  • Related