- 创建DownloadHandlers
- DownloadHandlerBuffer
- 例
- DownloadHandlerFile
- 例
- DownloadHandlerTexture
- 例
- DownloadHandlerAssetBundle
- 例
- DownloadHandlerAudioClip
- 例
- DownloadHandlerMovieTexture
- 例
- DownloadHandlerScript
- 避免垃圾收集开销
- 例
创建DownloadHandlers
有几种类型的DownloadHandlers:
• DownloadHandlerBuffer 用于简单的数据存储。• DownloadHandlerFile 用于下载文件并将其保存到内存较少的磁盘。• DownloadHandlerTexture 用于下载图像。• DownloadHandlerAssetBundle 用于提取AssetBundles。• DownloadHandlerAudioClip 用于下载音频文件。• DownloadHandlerMovieTexture 用于下载视频文件。•DownloadHandlerScript是一个特殊的班级。就其本身而言,它什么都不做。但是,该类可以由用户定义的类继承。该类接收来自UnityWebRequest系统的回调,然后可以用它来完成从网络到达的数据的完全自定义处理。
这些API与DownloadHandlerTexture接口类似。
UnityWebRequest有一个属性disposeDownloadHandlerOnDispose,默认为true。如果此属性为true,则在处置UnityWebRequest对象时,Dispose()也将在附加的下载处理程序上调用,从而使其无效。如果您保留对下载处理程序的引用超过对UnityWebRequest的引用,则应将disposeDownloadHandlerOnDispose设置为false。
DownloadHandlerBuffer
这个下载处理程序是最简单的,并处理大部分用例。它将接收到的数据存储在本机代码缓冲区中。下载完成后,您可以以字节数组或字符串的形式访问缓冲的数据。
例
using UnityEngine;using UnityEngine.Networking;using System.Collections;public class MyBehaviour : MonoBehaviour {void Start() {StartCoroutine(GetText());}IEnumerator GetText() {UnityWebRequest www = new UnityWebRequest("http://www.my-server.com");www.downloadHandler = new DownloadHandlerBuffer();yield return www.SendWebRequest();if(www.isNetworkError || www.isHttpError) {Debug.Log(www.error);}else {// Show results as textDebug.Log(www.downloadHandler.text);// Or retrieve results as binary databyte[] results = www.downloadHandler.data;}}}
DownloadHandlerFile
这是一个特殊的大文件下载处理程序。它将下载的字节直接写入文件,因此无论正在下载的文件的大小如何,内存使用率都很低。与其他下载处理程序的区别是,您无法从中获取数据,所有数据都保存到文件中。
例
using System.Collections;using System.IO;using UnityEngine;using UnityEngine.Networking;public class FileDownloader : MonoBehaviour {void Start () {StartCoroutine(DownloadFile());}IEnumerator DownloadFile() {var uwr = new UnityWebRequest("https://unity3d.com/", UnityWebRequest.kHttpVerbGET);string path = Path.Combine(Application.persistentDataPath, "unity3d.html");uwr.downloadHandler = new DownloadHandlerFile(path);yield return uwr.SendWebRequest();if (uwr.isNetworkError || uwr.isHttpError)Debug.LogError(uwr.error);elseDebug.Log("File successfully downloaded and saved to " + path);}}
DownloadHandlerTexture
不使用DownloadHandlerBuffer来下载图像文件,然后使用原始字节创建纹理Texture.LoadImage,而是使用效率更高DownloadHandlerTexture。
该下载处理程序将收到的数据存储在UnityEngine.Texture。完成下载后,它会将JPEG和PNG解码为有效UnityEngine.Texture objects。UnityEngine.Texture每个DownloadHandlerTexture对象只创建一个副本。这减少了垃圾收集的性能命中。该处理程序在本地代码中执行缓冲,解压缩和纹理创建。此外,解压缩和纹理创建是在工作线程而不是主线程上执行的,这可以在加载大纹理时提高帧时间。
最后,DownloadHandlerTexture在最终创建Texture本身时只分配托管内存,这消除了与在脚本中执行字节到纹理转换相关的垃圾回收开销。
例
以下示例从互联网下载PNG文件,将其转换为Sprite并将其分配给图像:
using UnityEngine;using UnityEngine.UI;using UnityEngine.Networking;using System.Collections;[RequireComponent(typeof(UnityEngine.UI.Image))]public class ImageDownloader : MonoBehaviour {UnityEngine.UI.Image _img;void Start () {_img = GetComponent<UnityEngine.UI.Image>();Download("http://www.mysite.com/myimage.png");}public void Download(string url) {StartCoroutine(LoadFromWeb(url));}IEnumerator LoadFromWeb(string url){UnityWebRequest wr = new UnityWebRequest(url);DownloadHandlerTexture texDl = new DownloadHandlerTexture(true);wr.downloadHandler = texDl;yield return wr.SendWebRequest();if(!(wr.isNetworkError || wr.isHttpError)) {Texture2D t = texDl.texture;Sprite s = Sprite.Create(t, new Rect(0, 0, t.width, t.height),Vector2.zero, 1f);_img.sprite = s;}}}
DownloadHandlerAssetBundle
这个专门的下载处理程序的好处是它能够将数据流式传输到Unity的AssetBundle系统。一旦AssetBundle系统收到足够的数据,AssetBundle就可以作为一个UnityEngine.AssetBundle对象使用。只UnityEngine.AssetBundle创建一个对象的副本。这大大减少了运行时内存分配以及加载AssetBundle时的内存影响。它还允许AssetBundles在未完全下载的情况下部分使用,因此您可以对资产进行流式处理。
所有下载和解压缩都发生在工作线程上。
AssetBundles通过一个DownloadHandlerAssetBundle对象下载,该对象有一个特殊的assetBundle属性来检索AssetBundle。
由于AssetBundle系统的工作方式,所有AssetBundle必须有一个与它们相关的地址。通常,这是它们所在的名义URL(意味着任何重定向之前的URL)。几乎在所有情况下,您应该传递给您传递给UnityWebRequest的相同URL。使用高级API(HLAPI)时,这是为您完成的。
例
using UnityEngine;using UnityEngine.Networking;using System.Collections;public class MyBehaviour : MonoBehaviour {void Start() {StartCoroutine(GetAssetBundle());}IEnumerator GetAssetBundle() {UnityWebRequest www = new UnityWebRequest("http://www.my-server.com");DownloadHandlerAssetBundle handler = new DownloadHandlerAssetBundle(www.url, uint.MaxValue);www.downloadHandler = handler;yield return www.SendWebRequest();if(www.isNetworkError || www.isHttpError) {Debug.Log(www.error);}else {// Extracts AssetBundleAssetBundle bundle = handler.assetBundle;}}}
DownloadHandlerAudioClip
该下载处理程序经过优化,可用于下载音频文件。您可以使用此下载处理程序以更方便的方式执行,而不是使用下载原始字节DownloadHandlerBuffer然后创建AudioClip它们。
例
using System.Collections;using UnityEngine;using UnityEngine.Networking;public class AudioDownloader : MonoBehaviour {void Start () {StartCoroutine(GetAudioClip());}IEnumerator GetAudioClip() {using (var uwr = UnityWebRequestMultimedia.GetAudioClip("http://myserver.com/mysound.ogg", AudioType.OGGVORBIS)) {yield return uwr.SendWebRequest();if (uwr.isNetworkError || uwr.isHttpError) {Debug.LogError(uwr.error);yield break;}AudioClip clip = DownloadHandlerAudioClip.GetContent(uwr);// use audio clip}}}
DownloadHandlerMovieTexture
该下载处理程序经过优化以下载视频文件。您可以使用此下载处理程序以更方便的方式执行,而不是使用下载原始字节DownloadHandlerBuffer然后创建MovieTexture它们。
例
using System.Collections;using UnityEngine;using UnityEngine.Networking;public class MovieDownloader : MonoBehaviour {void Start () {StartCoroutine(GetAudioClip());}IEnumerator GetAudioClip() {using (var uwr = UnityWebRequestMultimedia.GetMovieTexture("http://myserver.com/mysound.ogg")) {yield return uwr.SendWebRequest();if (uwr.isNetworkError || uwr.isHttpError) {Debug.LogError(uwr.error);yield break;}MovieTexture movie = DownloadHandlerMovieTexture.GetContent(uwr);// use movie texture}}}
DownloadHandlerScript
对于需要完全控制下载数据处理的用户,Unity提供DownloadHandlerScript该类。
默认情况下,这个类的实例什么都不做。但是,如果您从中派生自己的类DownloadHandlerScript,则可能会覆盖某些函数,并在数据从网络到达时使用它们来接收回调。
注意:实际下载发生在工作线程上,但所有DownloadHandlerScript回调都在主线程上运行。避免在这些回调期间执行计算量大的操作。
覆盖的功能**ReceiveContentLength()**
protected void ReceiveContentLength(long contentLength);
这个函数在收到Content-Length头时被调用。请注意,如果您的服务器在处理UnityWebRequest的过程中发送一个或多个重定向响应,则可能会多次发生此回调。
OnContentComplete()
protected void OnContentComplete();
当UnityWebRequest从服务器完全下载所有数据并将所有接收到的数据转发给ReceiveData回调时,将调用此函数。
receiveData()
protected bool ReceiveData(byte[] data, long dataLength);
该数据从远程服务器到达后调用,每帧调用一次。该data参数包含从远程服务器接收到的原始字节,并dataLength指示数据数组中新数据的长度。
当不使用预先分配的数据缓冲区时,系统每次调用此回调时都会创建一个新的字节数组,并且dataLength始终等于data.Length。使用预先分配的数据缓冲区时,数据缓冲区将被重用,并且dataLength必须用于查找更新的字节数。
该函数需要返回值为true或false。如果您返回false,系统将立即中止UnityWebRequest。如果返回true,则处理正常继续。
避免垃圾收集开销
Unity的许多更高级用户都关心减少垃圾回收造成的CPU峰值。对于这些用户,UnityWebRequest系统允许预先分配托管代码字节数组,该数组用于将下载的数据传递给DownloadHandlerScript的ReceiveData回调函数。
在使用DownloadHandlerScript派生类捕获下载的数据时,使用此函数可以完全消除托管代码内存分配。
要DownloadHandlerScript使用预先分配的托管缓冲区进行操作,请向其构造函数提供一个字节数组DownloadHandlerScript。
注意:字节数组的大小限制了每帧传送给ReceiveData回调的数据量。如果数据缓慢到达,在很多帧中,您可能提供了太小的字节数组。
例
using UnityEngine;using UnityEngine.Networking;using System.Collections;public class LoggingDownloadHandler : DownloadHandlerScript {// Standard scripted download handler - allocates memory on each ReceiveData callbackpublic LoggingDownloadHandler(): base() {}// Pre-allocated scripted download handler// reuses the supplied byte array to deliver data.// Eliminates memory allocation.public LoggingDownloadHandler(byte[] buffer): base(buffer) {}// Required by DownloadHandler base class. Called when you address the 'bytes' property.protected override byte[] GetData() { return null; }// Called once per frame when data has been received from the network.protected override bool ReceiveData(byte[] data, int dataLength) {if(data == null || data.Length < 1) {Debug.Log("LoggingDownloadHandler :: ReceiveData - received a null/empty buffer");return false;}Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveData - received {0} bytes", dataLength));return true;}// Called when all data has been received from the server and delivered via ReceiveData.protected override void CompleteContent() {Debug.Log("LoggingDownloadHandler :: CompleteContent - DOWNLOAD COMPLETE!");}// Called when a Content-Length header is received from the server.protected override void ReceiveContentLength(int contentLength) {Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveContentLength - length {0}", contentLength));}}
?
