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:
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);
            }
        }






你可能感兴趣的:(unity)