• 创建DownloadHandlers
    • DownloadHandlerBuffer
    • DownloadHandlerFile
    • DownloadHandlerTexture
    • DownloadHandlerAssetBundle
    • DownloadHandlerAudioClip
    • DownloadHandlerMovieTexture
    • DownloadHandlerScript
    • 避免垃圾收集开销

    创建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. }

    ?