有几种类型的 DownloadHandlers
DownloadHandlerBuffer
用于简单的數據存儲。DownloadHandlerFile
用于将文件下载并保存到磁盘,内存占用量低。DownloadHandlerTexture
用于下载图像。DownloadHandlerAssetBundle
用于获取 AssetBundles。DownloadHandlerAudioClip
用于下载音频文件。DownloadHandlerMovieTexture
用于下载视频文件。建议使用 VideoPlayer 进行视频下载和电影播放,因为 MovieTexture 已被弃用。DownloadHandlerScript
是一个特殊的类。它本身不执行任何操作。但是,此类可以被用户定义的类继承。此类接收来自 UnityWebRequest 系统的回调,这些回调可用于在数据从网络到达时执行完全自定义的数据处理。API 与 DownloadHandlerTexture
的接口类似。
UnityWebRequest
具有一个属性 disposeDownloadHandlerOnDispose
,默认值为 true。如果此属性为 true,当 UnityWebRequest 对象被处置时,Dispose() 也将在附加的下载处理程序上调用,使其失效。如果您对下载处理程序的引用时间比对 UnityWebRequest 的引用时间长,则应将 disposeDownloadHandlerOnDispose 设置为 false。
此下载处理程序是最简单的,并且处理大多数用例。它将接收到的数据存储在本地代码缓冲区中。下载完成后,您可以将缓冲数据作为字节数组或文本字符串访问。
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
public class MyBehaviour : MonoBehaviour {
void Start() {
StartCoroutine(GetText());
}
IEnumerator GetText() {
UnityWebRequest www = new UnityWebRequest("https://www.my-server.com");
www.downloadHandler = new DownloadHandlerBuffer();
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success) {
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;
}
}
}
这是一个用于大型文件的特殊下载处理程序。它将下载的字节直接写入文件,因此无论下载的文件大小如何,内存使用量都保持较低。与其他下载处理程序的区别在于,您无法从此下载处理程序中获取数据,所有数据都保存到文件中。
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.result != UnityWebRequest.Result.Success)
Debug.LogError(uwr.error);
else
Debug.Log("File successfully downloaded and saved to " + path);
}
}
与使用 DownloadHandlerBuffer
下载图像文件,然后使用 Texture.LoadImage
从原始字节创建纹理相比,使用 DownloadHandlerTexture
更有效率。
此下载处理程序将接收到的数据存储在 UnityEngine.Texture
中。下载完成后,它将 JPEG 和 PNG 解码为有效的 UnityEngine.Texture 对象
。每个 DownloadHandlerTexture
对象只创建一个 UnityEngine.Texture
的副本。这减少了垃圾回收的性能损失。处理程序在本地代码中执行缓冲、解压缩和纹理创建。此外,解压缩和纹理创建是在工作线程而不是主线程上执行的,这可以提高加载大型纹理时的帧时间。
最后,DownloadHandlerTexture
仅在最终创建 Texture 本身时才分配托管内存,这消除了在脚本中执行字节到纹理转换时与垃圾回收相关的开销。
以下示例从互联网下载一个 PNG 文件,将其转换为 精灵2D 图形对象。如果您习惯于在 3D 中工作,精灵本质上只是标准纹理,但存在用于组合和管理精灵纹理的特殊技术,以提高开发过程中的效率和便捷性。 更多信息
见 词汇表,并将其分配给 图像
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Collections;
[RequireComponent(typeof(Image))]
public class ImageDownloader : MonoBehaviour {
Image _img;
void Start () {
_img = GetComponent<UnityEngine.UI.Image>();
Download("https://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.result == UnityWebRequest.Result.Success) {
Texture2D t = texDl.texture;
Sprite s = Sprite.Create(t, new Rect(0, 0, t.width, t.height),
Vector2.zero, 1f);
_img.sprite = s;
}
}
}
此专用下载处理程序的优势在于,它能够将数据流式传输到 Unity 的 AssetBundle 系统。一旦 AssetBundle 系统接收了足够的数据,AssetBundle 就可以作为 UnityEngine.AssetBundle
对象使用。只创建一个 UnityEngine.AssetBundle
对象的副本。这大大减少了运行时内存分配,以及加载 AssetBundle 的内存影响。它还允许在未完全下载的情况下部分使用 AssetBundles,因此您可以流式传输 Assets。
所有下载和解压缩都在工作线程上进行。
AssetBundles 通过 DownloadHandlerAssetBundle
对象下载,该对象具有一个特殊的 assetBundle
属性来检索 AssetBundle。
由于 AssetBundle 系统的工作方式,所有 AssetBundle 都必须与它们关联一个地址。通常,这是它们所在的标称 URL(即重定向之前的 URL)。在几乎所有情况下,您应该传递与传递给 UnityWebRequest 相同的 URL。当使用 高级 API用于构建 Unity 游戏多人功能的系统。它建立在低级传输实时通信层之上,并处理多人游戏所需的许多常见任务。 更多信息
见 词汇表 (HLAPI) 时,将为您完成此操作。
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
public class MyBehaviour : MonoBehaviour {
void Start() {
StartCoroutine(GetAssetBundle());
}
IEnumerator GetAssetBundle() {
UnityWebRequest www = new UnityWebRequest("https://www.my-server.com");
DownloadHandlerAssetBundle handler = new DownloadHandlerAssetBundle(www.url, uint.MaxValue);
www.downloadHandler = handler;
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success) {
Debug.Log(www.error);
}
else {
// Extracts AssetBundle
AssetBundle bundle = handler.assetBundle;
}
}
}
此下载处理程序针对下载音频文件进行了优化。与使用 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("https://myserver.com/mysound.ogg", AudioType.OGGVORBIS)) {
yield return uwr.SendWebRequest();
if (uwr.result != UnityWebRequest.Result.Success) {
Debug.LogError(uwr.error);
yield break;
}
AudioClip clip = DownloadHandlerAudioClip.GetContent(uwr);
// use audio clip
}
}
}
对于需要完全控制下载数据处理的用户,Unity 提供了 DownloadHandlerScript
类。
默认情况下,此类的实例不执行任何操作。但是,如果您从 DownloadHandlerScript
派生自己的类,则可以覆盖某些函数,并使用它们在数据从网络到达时接收回调。
注意:实际下载是在工作线程上进行的,但所有 DownloadHandlerScript
回调都在主线程上运行。在这些回调期间,避免执行计算量大的操作。
protected void ReceiveContentLength(long contentLength);
当接收到 Content-Length 标头时,会调用此函数。请注意,如果您的服务器在处理 UnityWebRequest 的过程中发送一个或多个重定向响应,则此回调可能会多次发生。
protected void OnContentComplete();
当 UnityWebRequest 已从服务器完全下载所有数据,并将所有接收到的数据转发到 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;
public class LoggingDownloadHandler : DownloadHandlerScript {
// Standard scripted download handler - allocates memory on each ReceiveData callback
public 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 ReceiveContentLengthHeader(ulong contentLength) {
Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveContentLength - length {0}", contentLength));
}
}