WWW需要注意的問題

1.WWW.LoadFromCacheOrDownload的侷限性

WWW.LoadFromCacheOrDownload只能用於AssetBundle類型,而且只有這些屬性有值,且訪問不會報錯:
assetBundle, progress, error, url, Dispose()

其它的函數和屬性都會報錯,size、bytesDownloaded、bytes、audioClip ...

很多人都在這個地方耗費了不少時間,這麼不友好的設計真是要不得。

2.WWW.EscapURL的純粹性

C#中類似的功能叫做UrlEncode,這類函數的用途只是對path和query部分進行編碼,而不是對整個url編碼。

例如:
http://www.baidu.com/下載完畢
編碼就變成:
http%3a%2f%2fwww.baidu.com%2f%e4%b8%8b%e8%bd%bd%e5%ae%8c%e6%af%95
這樣的url地址,瀏覽器不認,所有的程序都不認,一定要注意。

WWW.EscapURL就是個純粹的編碼函數,如果已經編碼了,再次調用會重複編碼,不會智能檢測。

WWW手冊說
Note: URL must be '%' escaped.
經測試,未編碼的url也可以,可能是新版內部已經自動對url智能編碼。


3.在WWW加載過程中訪問其屬性要慎重

在WWW.isDone返回true之前,好多屬性的訪問會報錯:assetBundle,audioClip, bytes ...
在加載過程中,訪問這些屬性不會報錯:isDone, progress, uploadProgress, error,  url

尤其注意:如果網絡比較卡,在加載過程中訪問bytesDownloaded不僅會報錯,而且卡死整個主線程。我本來想用bytesDownloaded除以已知的size得到加載進度,看來只能用WWW.progress了。


4.同步和異步問題

不管有沒有使用yield return www,WWW都是異步加載的。但推薦使用yield,經測試發現不使用協程序,如下代碼就會造成卡頓:

客戶端代碼Test.cs:
public class Test : MonoBehaviour
{
    WWW www;
    float time;

    void Update()
    {
        string url = "http://127.0.0.1/1.php";
        if (www == null)
        {
            time = Time.time;
            www = new WWW(url);//會卡頓
            //StartCoroutine(load(url));//不會卡頓
        }
        if (Time.time - time > 1f)
        {
            Debug.Log("timeout");
            www.Dispose();
            www = null;
        }
    }

    IEnumerator load(string url)
    {
        www = new WWW(url);
        yield return www;
    }
}

服務端代碼1.php:
<?php
sleep(2);//延遲2秒
echo "hello world!";


5.加載線程和主線程

我使用了yield return www,然後又在主線程中Update中不停的檢測www的屬性,於是就發生了下面的錯誤。

get_assetBundle can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.

這段話的意思是不要在成員變量聲明的時候和構造函數裏面調用unity對象的屬性,因爲成員變量聲明和構造函數是在“加載線程”中的,unity變量的屬性只能在主線程中調用,協程的執行不在主線程中,所以出現此錯誤?

下面這句話會報錯:
public static DirectoryInfo dir = new DirectoryInfo(Application.persistentDataPath + "/");


6.WWW不僅僅是個加載器

WWW不僅不數據從網絡或本地磁盤加載到內存,而且還對assetBundle(lzma壓縮包)進行了解壓縮。我以前認爲不僅解壓縮,而且還把texture、audio等資源解碼出來,其實沒有,text、bytes、texture等屬性是調用的時候才動態解碼出來的。

WWW做的事情不夠純粹,好處是方便,壞處是耦合,試想手遊更新過程:把資源從網絡上下載下來,然後寫入本地磁盤,這個過程根本不需要對assetBundle解壓縮。好在要更新的內容一般不是很多,更新完畢可以立即釋放assetBundle,就不必單獨用HttpClient等類進行更新了。


7.不要反覆直接調用WWW的屬性

反編譯WWW的源碼可以看到text、bytes、texture等屬性是動態獲取的,沒調用一次就要重新計算一次。

        public string text
        {
          get{
                if (!this.isDone)
                {
                    throw new UnityException("WWW is not ready downloading yet");
                }
                byte[] bytes = this.bytes;
                return this.GetTextEncoder().GetString(bytes, 0, bytes.Length);
            }
        }

        public extern byte[] bytes
        {
            [WrapperlessIcall]
            [MethodImpl(MethodImplOptions.InternalCall)]
            get;
        }

        public Texture2D texture
        {
            get
            {
                return this.GetTexture(false);
            }
        }






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章