Search Unity

  1. Unity 2020.1 has been released.
    Dismiss Notice
  2. We are looking for feedback on the experimental Unity Safe Mode which is aiming to help you resolve compilation errors faster during project startup.
    Dismiss Notice
  3. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Can't Start Coroutine Inside of .GetDownloadUrlAsync() method?

Discussion in 'Scripting' started by jacksonbarnes, Aug 1, 2019.

  1. jacksonbarnes


    Sep 13, 2017
    So I know I probably can't start a coroutine using a separate thread (if that's even how you say it), but I would like to why this is not possible and if there is a way around this? Below is the code. (The code in a nutshell) I'm basically getting a direct link from firebase using the .GetDownloadUrlAsync() method than trying to download an asset bundle using a coroutine.

    Code (CSharp):
    1. public void GetTargetOnFound(ImageTarget targetInfo)
    2.     {
    3.         string assetBundleName = "assetbundle";
    4.         string assetBundleEndpoint = _storageUrl + "/" + targetInfo.Name + "/" + assetBundleName;
    6.         StorageReference _Ref = _storage.GetReferenceFromUrl(assetBundleEndpoint);
    8.         _Ref.GetDownloadUrlAsync().ContinueWith((Task<Uri> task) =>
    9.         {
    10.             if (!task.IsFaulted && !task.IsCanceled)
    11.             {
    12.                 StartCoroutine(HandleDownloadAssets(task.Result.AbsoluteUri, assetBundleName));
    13.             }
    14.         });
    15.     }
    17.     IEnumerator HandleDownloadAssets(string assetBundleEndpoint, string assetBundleName)
    18.     {
    19.         UnityWebRequest www = UnityWebRequestAssetBundle.GetAssetBundle(assetBundleEndpoint);
    20.         yield return www.SendWebRequest();
    22.         if (www.isNetworkError || www.isHttpError)
    23.         {
    24.             Debug.Log(www.error);
    25.         }
    26.         else
    27.         {
    28.             AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(www);
    29.             var prefab = bundle.LoadAsset<GameObject>(assetBundleName);
    30.             Instantiate(prefab, _imageTrackable.transform);
    31.         }
    32.     }
    Any ideas? Thanks!
  2. Kurt-Dekker


    Mar 16, 2013
    The standard way to do this is to have a list of delegates (such as a List<System.Action>) that you lock() and check in your Update() loop.

    If that list is ever not-empty, it copies all the delegates into a separate list, then clears the list and unlocks it.

    Now with the copied delegates, iterate them and run each delegate, because now you are on the main thread.

    To get the delegates into this list, you would in the async handler above:

    - create the delegate to do what you want (i.e., start the coroutine with a given context and data payload)
    - lock the list
    - add the delegate to the list
    - unlock the list

    Effectively you are preparing a little blob of code to start your coroutine, then putting it in a list for the main thread (running Update()) to do for you at its next opportunity.

    You can actually use something like Thread Ninja from the Unity asset store for a more-general solution to this, or just implement the simple steps above.
    KateKim and jacksonbarnes like this.