创建DownloadHandlers

有几种类型的DownloadHandlers

  1. DownloadHandlerBuffer 用于简单的数据存储。
  2. DownloadHandlerFile 用于下载文件并将其保存到内存较少的磁盘。
  3. DownloadHandlerTexture 用于下载图像。
  4. DownloadHandlerAssetBundle 用于提取AssetBundles
  5. DownloadHandlerAudioClip 用于下载音频文件。
  6. DownloadHandlerMovieTexture 用于下载视频文件。
  7. DownloadHandlerScript是一个特殊的班级。就其本身而言,它什么都不做。但是,该类可以由用户定义的类继承。该类接收来自UnityWebRequest系统的回调,然后可以用它来完成从网络到达的数据的完全自定义处理。

这些API与DownloadHandlerTexture接口类似。

UnityWebRequest有一个属性disposeDownloadHandlerOnDispose,默认为true。如果此属性为true,则在处置UnityWebRequest对象时,Dispose()也将在附加的下载处理程序上调用,从而使其无效。如果您保留对下载处理程序的引用超过对UnityWebRequest的引用,则应将disposeDownloadHandlerOnDispose设置为false

DownloadHandlerBuffer

这个下载处理程序是最简单的,并处理大部分用例。它将接收到的数据存储在本机代码缓冲区中。下载完成后,您可以以字节数组或字符串的形式访问缓冲的数据。

  1. using UnityEngine;
  2. using UnityEngine.Networking;
  3. using System.Collections;
  4. public class MyBehaviour : MonoBehaviour {
  5. void Start() {
  6. StartCoroutine(GetText());
  7. }
  8. IEnumerator GetText() {
  9. UnityWebRequest www = new UnityWebRequest("http://www.my-server.com");
  10. www.downloadHandler = new DownloadHandlerBuffer();
  11. yield return www.SendWebRequest();
  12. if(www.isNetworkError || www.isHttpError) {
  13. Debug.Log(www.error);
  14. }
  15. else {
  16. // Show results as text
  17. Debug.Log(www.downloadHandler.text);
  18. // Or retrieve results as binary data
  19. byte[] results = www.downloadHandler.data;
  20. }
  21. }
  22. }

DownloadHandlerFile

这是一个特殊的大文件下载处理程序。它将下载的字节直接写入文件,因此无论正在下载的文件的大小如何,内存使用率都很低。与其他下载处理程序的区别是,您无法从中获取数据,所有数据都保存到文件中。

  1. using System.Collections;
  2. using System.IO;
  3. using UnityEngine;
  4. using UnityEngine.Networking;
  5. public class FileDownloader : MonoBehaviour {
  6. void Start () {
  7. StartCoroutine(DownloadFile());
  8. }
  9. IEnumerator DownloadFile() {
  10. var uwr = new UnityWebRequest("https://unity3d.com/", UnityWebRequest.kHttpVerbGET);
  11. string path = Path.Combine(Application.persistentDataPath, "unity3d.html");
  12. uwr.downloadHandler = new DownloadHandlerFile(path);
  13. yield return uwr.SendWebRequest();
  14. if (uwr.isNetworkError || uwr.isHttpError)
  15. Debug.LogError(uwr.error);
  16. else
  17. Debug.Log("File successfully downloaded and saved to " + path);
  18. }
  19. }

DownloadHandlerTexture

不使用DownloadHandlerBuffer来下载图像文件,然后使用原始字节创建纹理Texture.LoadImage,而是使用效率更高DownloadHandlerTexture

该下载处理程序将收到的数据存储在UnityEngine.Texture。完成下载后,它会将JPEG和PNG解码为有效UnityEngine.Texture objectsUnityEngine.Texture每个DownloadHandlerTexture对象只创建一个副本。这减少了垃圾收集的性能命中。该处理程序在本地代码中执行缓冲,解压缩和纹理创建。此外,解压缩和纹理创建是在工作线程而不是主线程上执行的,这可以在加载大纹理时提高帧时间。

最后,DownloadHandlerTexture在最终创建Texture本身时只分配托管内存,这消除了与在脚本中执行字节到纹理转换相关的垃圾回收开销。

以下示例从互联网下载PNG文件,将其转换为Sprite并将其分配给图像:

  1. using UnityEngine;
  2. using UnityEngine.UI;
  3. using UnityEngine.Networking;
  4. using System.Collections;
  5. [RequireComponent(typeof(UnityEngine.UI.Image))]
  6. public class ImageDownloader : MonoBehaviour {
  7. UnityEngine.UI.Image _img;
  8. void Start () {
  9. _img = GetComponent<UnityEngine.UI.Image>();
  10. Download("http://www.mysite.com/myimage.png");
  11. }
  12. public void Download(string url) {
  13. StartCoroutine(LoadFromWeb(url));
  14. }
  15. IEnumerator LoadFromWeb(string url)
  16. {
  17. UnityWebRequest wr = new UnityWebRequest(url);
  18. DownloadHandlerTexture texDl = new DownloadHandlerTexture(true);
  19. wr.downloadHandler = texDl;
  20. yield return wr.SendWebRequest();
  21. if(!(wr.isNetworkError || wr.isHttpError)) {
  22. Texture2D t = texDl.texture;
  23. Sprite s = Sprite.Create(t, new Rect(0, 0, t.width, t.height),
  24. Vector2.zero, 1f);
  25. _img.sprite = s;
  26. }
  27. }
  28. }

DownloadHandlerAssetBundle

这个专门的下载处理程序的好处是它能够将数据流式传输到Unity的AssetBundle系统。一旦AssetBundle系统收到足够的数据,AssetBundle就可以作为一个UnityEngine.AssetBundle对象使用。只UnityEngine.AssetBundle创建一个对象的副本。这大大减少了运行时内存分配以及加载AssetBundle时的内存影响。它还允许AssetBundles在未完全下载的情况下部分使用,因此您可以对资产进行流式处理。

所有下载和解压缩都发生在工作线程上。

AssetBundles通过一个DownloadHandlerAssetBundle对象下载,该对象有一个特殊的assetBundle属性来检索AssetBundle

由于AssetBundle系统的工作方式,所有AssetBundle必须有一个与它们相关的地址。通常,这是它们所在的名义URL(意味着任何重定向之前的URL)。几乎在所有情况下,您应该传递给您传递给UnityWebRequest的相同URL。使用高级API(HLAPI)时,这是为您完成的。

  1. using UnityEngine;
  2. using UnityEngine.Networking;
  3. using System.Collections;
  4. public class MyBehaviour : MonoBehaviour {
  5. void Start() {
  6. StartCoroutine(GetAssetBundle());
  7. }
  8. IEnumerator GetAssetBundle() {
  9. UnityWebRequest www = new UnityWebRequest("http://www.my-server.com");
  10. DownloadHandlerAssetBundle handler = new DownloadHandlerAssetBundle(www.url, uint.MaxValue);
  11. www.downloadHandler = handler;
  12. yield return www.SendWebRequest();
  13. if(www.isNetworkError || www.isHttpError) {
  14. Debug.Log(www.error);
  15. }
  16. else {
  17. // Extracts AssetBundle
  18. AssetBundle bundle = handler.assetBundle;
  19. }
  20. }
  21. }

DownloadHandlerAudioClip

该下载处理程序经过优化,可用于下载音频文件。您可以使用此下载处理程序以更方便的方式执行,而不是使用下载原始字节DownloadHandlerBuffer然后创建AudioClip它们。

  1. using System.Collections;
  2. using UnityEngine;
  3. using UnityEngine.Networking;
  4. public class AudioDownloader : MonoBehaviour {
  5. void Start () {
  6. StartCoroutine(GetAudioClip());
  7. }
  8. IEnumerator GetAudioClip() {
  9. using (var uwr = UnityWebRequestMultimedia.GetAudioClip("http://myserver.com/mysound.ogg", AudioType.OGGVORBIS)) {
  10. yield return uwr.SendWebRequest();
  11. if (uwr.isNetworkError || uwr.isHttpError) {
  12. Debug.LogError(uwr.error);
  13. yield break;
  14. }
  15. AudioClip clip = DownloadHandlerAudioClip.GetContent(uwr);
  16. // use audio clip
  17. }
  18. }
  19. }

DownloadHandlerMovieTexture

该下载处理程序经过优化以下载视频文件。您可以使用此下载处理程序以更方便的方式执行,而不是使用下载原始字节DownloadHandlerBuffer然后创建MovieTexture它们。

  1. using System.Collections;
  2. using UnityEngine;
  3. using UnityEngine.Networking;
  4. public class MovieDownloader : MonoBehaviour {
  5. void Start () {
  6. StartCoroutine(GetAudioClip());
  7. }
  8. IEnumerator GetAudioClip() {
  9. using (var uwr = UnityWebRequestMultimedia.GetMovieTexture("http://myserver.com/mysound.ogg")) {
  10. yield return uwr.SendWebRequest();
  11. if (uwr.isNetworkError || uwr.isHttpError) {
  12. Debug.LogError(uwr.error);
  13. yield break;
  14. }
  15. MovieTexture movie = DownloadHandlerMovieTexture.GetContent(uwr);
  16. // use movie texture
  17. }
  18. }
  19. }

DownloadHandlerScript

对于需要完全控制下载数据处理的用户,Unity提供DownloadHandlerScript该类。

默认情况下,这个类的实例什么都不做。但是,如果您从中派生自己的类DownloadHandlerScript,则可能会覆盖某些函数,并在数据从网络到达时使用它们来接收回调。

注意:实际下载发生在工作线程上,但所有DownloadHandlerScript回调都在主线程上运行。避免在这些回调期间执行计算量大的操作。

覆盖的功能**ReceiveContentLength()**

  1. protected void ReceiveContentLength(long contentLength);

这个函数在收到Content-Length头时被调用。请注意,如果您的服务器在处理UnityWebRequest的过程中发送一个或多个重定向响应,则可能会多次发生此回调。

OnContentComplete()

  1. protected void OnContentComplete();

当UnityWebRequest从服务器完全下载所有数据并将所有接收到的数据转发给ReceiveData回调时,将调用此函数。

receiveData()

  1. protected bool ReceiveData(byte[] data, long dataLength);

该数据从远程服务器到达后调用,每帧调用一次。该data参数包含从远程服务器接收到的原始字节,并dataLength指示数据数组中新数据的长度。

当不使用预先分配的数据缓冲区时,系统每次调用此回调时都会创建一个新的字节数组,并且dataLength始终等于data.Length。使用预先分配的数据缓冲区时,数据缓冲区将被重用,并且dataLength必须用于查找更新的字节数。

该函数需要返回值为truefalse。如果您返回false,系统将立即中止UnityWebRequest。如果返回true,则处理正常继续。

避免垃圾收集开销

Unity的许多更高级用户都关心减少垃圾回收造成的CPU峰值。对于这些用户,UnityWebRequest系统允许预先分配托管代码字节数组,该数组用于将下载的数据传递给DownloadHandlerScriptReceiveData回调函数。

在使用DownloadHandlerScript派生类捕获下载的数据时,使用此函数可以完全消除托管代码内存分配。

DownloadHandlerScript使用预先分配的托管缓冲区进行操作,请向其构造函数提供一个字节数组DownloadHandlerScript

注意:字节数组的大小限制了每帧传送给ReceiveData回调的数据量。如果数据缓慢到达,在很多帧中,您可能提供了太小的字节数组。

  1. using UnityEngine;
  2. using UnityEngine.Networking;
  3. using System.Collections;
  4. public class LoggingDownloadHandler : DownloadHandlerScript {
  5. // Standard scripted download handler - allocates memory on each ReceiveData callback
  6. public LoggingDownloadHandler(): base() {
  7. }
  8. // Pre-allocated scripted download handler
  9. // reuses the supplied byte array to deliver data.
  10. // Eliminates memory allocation.
  11. public LoggingDownloadHandler(byte[] buffer): base(buffer) {
  12. }
  13. // Required by DownloadHandler base class. Called when you address the 'bytes' property.
  14. protected override byte[] GetData() { return null; }
  15. // Called once per frame when data has been received from the network.
  16. protected override bool ReceiveData(byte[] data, int dataLength) {
  17. if(data == null || data.Length < 1) {
  18. Debug.Log("LoggingDownloadHandler :: ReceiveData - received a null/empty buffer");
  19. return false;
  20. }
  21. Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveData - received {0} bytes", dataLength));
  22. return true;
  23. }
  24. // Called when all data has been received from the server and delivered via ReceiveData.
  25. protected override void CompleteContent() {
  26. Debug.Log("LoggingDownloadHandler :: CompleteContent - DOWNLOAD COMPLETE!");
  27. }
  28. // Called when a Content-Length header is received from the server.
  29. protected override void ReceiveContentLength(int contentLength) {
  30. Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveContentLength - length {0}", contentLength));
  31. }
  32. }

?