Android crash when using multiple www

Platform: Android + GearVR
Device: Samsung S8+

Here is what I’m trying to do:

  1. Load several images from a folder of the phone.
  2. Use the image loaded and assign it as a sprite to a renderer sprite.

Working code:

  public void LoadImage(string filePath, SpriteRenderer targetSprite)
    {
        var texture = new Texture2D(interiorRenderImageSize, interiorRenderImageSize);
        texture.LoadImage(File.ReadAllBytes(filePath));
        texture.wrapMode = TextureWrapMode.Clamp; //WORKAROUND Altrimenti l'immagine ha un bordino bianco
        targetSprite.sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(.5f, .5f), 100);
    }

This is working. It has a huge hiccup when called, but it is working. I call this function six times, loading different images.

Not working code:

    private IEnumerator LoadCoroutine(string filePath, SpriteRenderer targetSprite)
    {
        WWW www = new WWW("file://" + filePath);

        while (!www.isDone)
            yield return new WaitForEndOfFrame();

        targetSprite.sprite = Sprite.Create(www.texture, new Rect(0, 0, www.texture.width, www.texture.height), new Vector2(.5f, .5f), 100);
        targetSprite.sprite.texture.wrapMode = TextureWrapMode.Clamp;
        yield return new WaitForEndOfFrame();
    }

If i call this function only 2 times, it will work. However, if i call this six times, the app will freeze, then crash. Sometimes it will only freeze.

This is where i call these functions:

 public void StartLoadImages()
    {
        string interiorPath = Application.isEditor ? Application.dataPath + "/TestFolder/Interiors/" : imageFolderInterior;
        print(interiorPath);
        DirectoryInfo dirInfo = new DirectoryInfo(interiorPath);
        foreach (var f in dirInfo.GetFiles("*" + imageFormat))
        {
            if (f.Name == front + imageFormat)
            {
                //LoadImage(f.FullName, frontSpriteRenderer);
                StartCoroutine(LoadCoroutine(f.FullName, frontSpriteRenderer));
            }
            else if (f.Name == rear + imageFormat)
            {
                //LoadImage(f.FullName, rearSpriteRenderer);
                StartCoroutine(LoadCoroutine(f.FullName, rearSpriteRenderer));
            }
            else if (f.Name == right + imageFormat)
            {
                //LoadImage(f.FullName, rightSpriteRenderer);
                StartCoroutine(LoadCoroutine(f.FullName, rightSpriteRenderer));
            }
            else if (f.Name == left + imageFormat)
            {
                //LoadImage(f.FullName, leftSpriteRenderer);
                StartCoroutine(LoadCoroutine(f.FullName, leftSpriteRenderer));
            }
            else if (f.Name == up + imageFormat)
            {
                //LoadImage(f.FullName, upSpriteRenderer);
                StartCoroutine(LoadCoroutine(f.FullName, upSpriteRenderer));
            }
            else if (f.Name == down + imageFormat)
            {
                //LoadImage(f.FullName, downSpriteRenderer);
                StartCoroutine(LoadCoroutine(f.FullName, downSpriteRenderer));
            }
        }
    }

I am wondering why www method is not working when called several times, i tried to split the calls (call 3 loads, wait for input, then call the other 3) but it still crashes.

First thing to try is to clean up the code a bit. The Unity WWW object actually implements the IDisposable interface, and your code does not .Dispose() of the WWW objects.

Ideally you would create and use the WWW object within a using() statement to handle exceptions and other ways of returning besides completion of the block.

Now that may not be the problem, but it’s a start. And don’t feel bad: 99.9% of all example code out there for Unity3D WWW abjectly fails to implement the IDisposable interface properly, which most of the time is fine, but isn’t guaranteed to work on all platforms. Maybe you found the platform it fails on.

The change to comply with .IDisposable via using() is pretty simple and does not require explicit .Dispose() calls. Use a construct like this:

 using(  WWW www = new WWW("file://" + filePath))
 {
   yield return www;
  //do what you need with the www object here...
 }

Note, there is no while() loop involved, and that is probably where you are locking up for whatever reason. Just yield on it like above, then use the returned value, unless it is an error, etc.

First of all thanks for your answer.

I cleaned the code like you suggested but it still crashes.
No exceptions launched and it crashes only on the phone, not in the editor.

Have a nice day.

What’s in the Android logs? Have you tried a debug build connected to profiler? Are your files very large?

I connected it to ADB. No exception launched.

I’ll try to connect it to the profiler later today.

Image format: png, jpg
Image size: 20 - 25 mb
Image resolution: 2048x2048 - 4096x4096

Here is what i tried:

  • I load only like 3-4 images no problem.
  • I yielded for every load coroutine to finish before starting a new one, but it still freezes right after the third/fourth image.
  • I tried other images.

Later I’ll try to build without the GearVR plugins.

Can you suggest another method to load images at runtime? Because with File.ReadAllBytes I have no way of knowing the size of the image. :frowning:

Also, you might want to try populating your code with a bunch of Debug.Log() calls (all with different strings) so you can figure out where it is actually stopping when running on the device and logging at logcat.