Version: 5.6
创建 UploadHandler
Networking Reference

创建 DownloadHandler

There are four types of DownloadHandlers:

  • DownloadHandlerBuffer 用于简单的数据存储。
  • DownloadHandlerTexture 用于下载图像。
  • DownloadHandlerAssetBundle 用于提取 AssetBundle。
  • DownloadHandlerScript 是一个特殊类。就其本身而言,不会执行任何操作。但是,此类可由用户定义的类继承。此类接收来自 UnityWebRequest 系统的回调,然后可以使用这些回调在数据从网络到达时执行完全自定义的数据处理。

A specialized Download Handler for Audio clips is also available. The APIs are similar to DownloadHandlerTexture’s interface.

DownloadHandlerBuffer

This Download Handler is the simplest, and handles the majority of use cases. It stores received data in a native code buffer. When the download is complete, you can access the buffered data either as an array of bytes or as a UTF8 string.

示例

using UnityEngine;
using UnityEngine.Networking; 
using System.Collections;

 
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.Send();
 
        if(www.isError) {
            Debug.Log(www.error);
        }
        else {
            // Show results as text
            Debug.Log(www.downloadHandler.text);
 
            // Or retrieve results as binary data
            byte[] results = www.downloadHandler.data;
        }
    }
}

DownloadHandlerTexture

相较于使用 DownloadHandlerBuffer 下载图像文件,然后再使用 Texture.LoadImage 从原始字节创建纹理,使用 DownloadHandlerTexture 会更有效。

此下载处理程序将接收的数据存储在 UnityEngine.Texture中。在下载完成时,它将 JPEG 和 PNG 解码为有效的 UnityEngine.Texture objects。每个 DownloadHandlerTexture 对象只创建一个 UnityEngine.Texture 副本。这样会减少垃圾收集的性能问题。此处理程序在本机代码中执行缓冲、解压缩和纹理创建。另外,解压缩和纹理创建任务在工作程序线程上而不是主线程上执行,这样可以在加载大型纹理时改善帧时间。

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

示例

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

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.Send();
        if(!wr.isError) {
            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 带来的内存影响。此下载处理程序还允许在未完全下载的情况下部分使用 AssetBundle,因此可以流式传输资源。

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

AssetBundle 通过 DownloadHandlerAssetBundle 对象进行下载,该对象具有特殊的 assetBundle 属性可用于检索 AssetBundle。

由于 AssetBundle 系统的工作方式,所有 AssetBundle 都必须具有关联的地址。通常,该地址是它们所在的名义 URL(表示任何重定向之前的 URL)。在几乎任何情况下,都应该传入与传递给 UnityWebRequest 相同的 URL。使用高级 API (HLAPI) 时,此操作将自动完成。

示例

using UnityEngine;
using UnityEngine.Networking; 
using System.Collections;
 
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.Send();
 
        if(www.isError) {
            Debug.Log(www.error);
        }
        else {
            // Extracts AssetBundle
            AssetBundle bundle = handler.assetBundle;
        }
    }
}

DownloadHandlerScript

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

默认情况下,此类的实例不执行任何操作。但是,如果您从 DownloadHandlerScript 派生自己的类,则可以重写某些函数并使用它们在数据从网络到达时接收回调。

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

要重写的函数

ReceiveContentLength()

protected void ReceiveContentLength(long contentLength);

This function is called when the Content Length header is received. Note that this callback may occur multiple times if your server sends one or more redirect responses over the course of processing your UnityWebRequest.

OnContentComplete()

protected void OnContentComplete();

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

ReceiveData()

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

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

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

此函数需要返回值 truefalse。如果返回 false__,系统会立即中止 UnityWebRequest。如果返回 true__,则处理将正常继续。

避免垃圾收集开销

Unity 的许多高级用户都会关注如何减少因垃圾收集而导致的 CPU 峰值。对于这些用户,UnityWebRequest 系统允许预先分配托管代码字节数组,该数组用于将下载的数据传递给 DownloadHandlerScript 的 ReceiveData 回调。

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

要让 DownloadHandlerScript 使用预先分配的托管缓冲区运行,请向 DownloadHandlerScript 的构造函数提供一个字节数组。

注意:字节数组的大小限制了每帧传递给 ReceiveData 回调的数据量。如果数据经过很多帧才缓慢到达,可能是因为提供的字节数组太小。

示例

using UnityEngine;
using UnityEngine.Networking; 
using System.Collections;

public class LoggingDownloadHandler : DownloadHandlerScript {

    // 标准脚本化下载处理程序 - 在每个 ReceiveData 回调时分配内存
   
    public LoggingDownloadHandler(): base() {
    }

    // 预先分配的脚本化下载处理程序
    // 重用提供的字节数组来传递数据。
    //消除内存分配。
    
    public LoggingDownloadHandler(byte[] buffer): base(buffer) {
    }

    //对于 DownloadHandler 基类而言是必需的。在处理"bytes"属性时调用。
    
    protected override byte[] GetData() { return null; }

    //从网络收到数据后每帧调用一次。
    
    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;
    }

    // 从服务器收到所有数据并通过 ReceiveData 传递后调用。
    
    protected override void CompleteContent() {
        Debug.Log("LoggingDownloadHandler :: CompleteContent - DOWNLOAD COMPLETE!");
    }

    // 从服务器收到 Content-Length 标头时调用。
    
    protected override void ReceiveContentLength(int contentLength) {
        Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveContentLength - length {0}", contentLength));
    }
}
创建 UploadHandler
Networking Reference