Search Unity

Async loading JSON file

Discussion in 'Scripting' started by mistergreen2016, Dec 5, 2019.

  1. mistergreen2016


    Dec 4, 2016
    Hey, I need to load a json file to place GOs based on the data.
    Now, I need to do this Async since I'm using AR that's using the main thread.

    Here's my typical Stream reader. I'm not sure how to go about this. I know there's a async await function for .NET 4.5 and I'm using Unity 2019.2.

    Code (CSharp):
    1.     private void PlaceObject()
    2.     {
    3.         Vector3 pos = placementPose.position;
    4.         Quaternion rot = placementPose.rotation;
    5.         ObjClass[] obj;
    7.         using (StreamReader stream = new StreamReader(Application.persistentDataPath + "/objects.json"))
    8.         {
    9.             string json = stream.ReadToEnd();
    10.             obj = JsonHelper.FromJson<ObjClass>(json);
    12.             //populate
    13.             container = Instantiate(TankObjectReference.Instance.tankObjectDictionary["ObjectContainer"], pos, rot) as GameObject;
    14.             foreach (ObjClass item in obj)
    15.             {
    16.                 //Debug.Log("****objectID: "+item.objectID);
    17.                 if (item.objectID != "")
    18.                 {
    20.                     try
    21.                     {
    22.                         GameObject objID = TankObjectReference.Instance.tankObjectDictionary[item.objectID];
    23.                         var p = item.pos;
    24.                         var r = item.rot;
    25.                         var scale = item.scale;
    27.                         var go = Instantiate(objID, container.transform) as GameObject;
    28.                         go.transform.localPosition = p;
    29.                         go.transform.localRotation = r;
    30.                         go.transform.localScale = scale;
    32.                     }
    33.                     catch
    34.                     {
    35.                         Debug.Log("obj doesn't exist");
    37.                     }
    40.                 }
    41.             }
    42.         }
    44.     }
  2. SomeGuy22


    Jun 3, 2011
    I'm not the most knowledgeable in this topic but I can give one idea. You want to find the thing taking the most time and inject wait time between it to give the illusion of "async" while still relying on the main thread. As long as there is enough wait time and the waits are frequent enough you can "splice" operations fairly easily using IEnumerator. I typically use the XML serializer instead of JSON, so I don't know if this is possible: try to read per line instead of ReadToEnd. If you can do that you can inject wait time between line reading using "yield return new WaitForSeconds(.1f)" or some arbitrary number. Your foreach loop that is already there is an obvious candidate for injecting these waits, you can save a lot of lag time by processing your Instantiate calls individually.

    If you've never used IEnumerator before you basically just make that the return value of your function--private IEnumerator PlaceObject(). Then use StartCoroutine(PlaceObject()) to start it. When it's an IEnumerator it must yield return something at some point. At the end you can just put yield return null, and it'll also yield return when you inject the waits. Just remember that you can no longer guarantee your operation will be done in any specific amount of time, and the place where you called StartCoroutine will still run to the end even while the function is yielding.
  3. AlexN2805


    Nov 27, 2019
    If you just want the stream to be read async, this should be fairly trivial. If you need to entire function to be async, you need to move the code to a separate async function.

    Code (CSharp):
    1. private async Task PlaceObject()
    2. {
    3.    ...
    4.    string json = await stream.ReadToEndAsync();
    5.    ...
    6. }