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