Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unity3d - Separate UI Thread for Android

In my VR app for Android Smartphones (I think it doesn't matter whether it is a VR app or not) I download 6 big images from Street View and built a skybox out of it. During this process the whole app incl. environment and UI freezes. After ~10sec the process is down and Street View is there.

How can I seperate the main processing from UI? So the phone is working, but should not freeze. This is a common web problem, but how can I solve this in Unity for Android?

Thank you!

code:

private byte[] GetStreetviewTexture(string url) {
WWW www = new WWW(url);

while (!www.isDone) ;

if (!string.IsNullOrEmpty(www.error))
{
    Debug.LogWarning("Unable to DL texture: " + www.error);
}
else
{
    bytes = www.texture.EncodeToPNG();
}
return bytes;
}
like image 943
fmielke Avatar asked Sep 26 '26 10:09

fmielke


1 Answers

You probably want to use an IEnumerator to thread it with a Unity Coroutine. If you're already using this, which I'm assuming you actually are - could it be a performance issue that freezes the device? If so, check the Unity profiler and/or Unity Remote. Coroutines are, like comments suggest, not a Thread - but emulates a threaded behaviour.

Basic Coroutine code:

void SomeMethod() {
    StartCoroutine(Threaded());
}

IEnumerator Threaded() {
    // Do something
    yield return new WaitForSeconds(3f);
}

Check out the WWW class and how to make an IEnumerator wait for download to complete


Update responding to OP's follow-up question:

How to tell when a Coroutine is done and get a value


Update responding to OPs follow-up follow-up question: This is a simplified example of your current logic/flow. NOTE: THIS DOES NOT WORK. Do not use this code as an example for how it's supposed to be done, I just want to illustrate the differences in how you should approach your problem.

void ButtonClicked() {
     SetTexture()
}

void SetTexture() {
    Texture texture = GetTexture()
    Object.texture = texture;
}

Texture GetTexture() {
    Texture texture;
    StartCoroutine(DownloadTexture((textureCallback) => {
        texture = textureCallback;
    }));
    return texture;
}

IEnumerator DownloadTexture(Action<Texture> callbackTexture)
{
    WWW www = new WWW(URL);
    yield return www;

    callback(www.texture);
}

Not only does this not work, because a Coroutine is run asyncronously with the rest of the code, but it's not a good approach for this task.

Instead of doing

Button click -> set texture -> start download -> error setting texture -> download finished

you want:

Button click -> download texture -> wait for it to be done -> set texture

Like this:

void ButtonClick() {
    StartCoroutine(DownloadTexture((callbackTexture) => {
        SetTexture(callbackTexture); // Will run SetTexture when Coroutine DownloadTexture is completed.
    }));
}

IEnumerator DownloadTexture(Action<Texture> callbackTexture)
{
    WWW www = new WWW(URL);
    yield return www;

    callback(www.texture);
}

void SetTexture(Texture texture) {
     object.texture = texture;
}

Note that this is just flow-code. Your code will look different, using byte[] instead of Texture and I don't know if you're using a Button to start the texture-setting. This can be any sort of trigger/starting point.

like image 63
Fredrik Schön Avatar answered Sep 28 '26 23:09

Fredrik Schön



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!