DownloadHandlers
には 4 種類あります。
DownloadHandlerBuffer
は簡易なデータストレージとして使用されます。DownloadHandlerTexture
は画像をダウンロードするために使用されます。DownloadHandlerAssetBundle
はアセットバンドルをフェッチするために使用されます。DownloadHandlerScript
は特殊クラスです。それ自体では何も行いません。ただし、このクラスはユーザー定義のクラスによって継承が可能です。 このクラスは UnityWebRequest システムからコールバックを受け取り、ネットワークからデータを取得したときに完全にカスタム処理するために使用します。オーディオクリップ専用のダウンロードハンドラーも利用できます。API は DownloadHandlerTexture
のインターフェースに似ています。
このダウンロードハンドラーは最も簡単で、ほとんどの使用事例を処理します。受け取ったデータをネイティブコードバッファに格納します。ダウンロードが完了すると、バイト配列、または UTF8 文字列でバッファされたデータにアクセスできます。
using UnityEngine;
using System.Collections;
using Unity.Networking;
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;
}
}
}
DownloadHandlerBuffer
を使用して画像ファイルをダウンロードし、それから Texture.LoadImage
を使用して生のバイトからテクスチャを作成する代わりに、DownloadHandlerTexture
を使用する方が効率的です。
このダウンロードハンドラーは、受信したデータを UnityEngine.Texture
に格納します。ダウンロードが完了すると、JPEG と PNG を有効な UnityEngine.Texture
オブジェクトにデコードします。各 DownloadHandlerTexture
オブジェクトごとに 1 つのUnityEngine.Texture
だけしか作成されません。ですから、ガベージコレクションによるパフォーマンスの低下を軽減します。ハンドラーは、バッファリング、解凍、テクスチャの作成をネイティブコードで実行します。さらに、解凍とテクスチャの作成を、メインスレッドでなくワーカースレッドで実行するため、大きなテクスチャを読み込むときにフレーム時間を向上させます。
最後に、DownloadHandlerTexture
は、最終的にテクスチャ自体を作成するときにのみマネージドのメモリを割り当てます。このため、スクリプトでバイトからテクスチャへの変換を実行する際のガベージコレクションのオーバーヘッドを排除します。
以下の例では、PNG ファイルをインターネットからダウンロードし、スプライトに変換し、画像 に割り当てます。
using UnityEngine;
using UnityEngine.UI;
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;
}
}
}
この特化したダウンロードハンドラーの利点は、Unity のアセットバンドルシステムにデータをストリーミングできることです。アセットバンドルシステムが十分なデータを受け取ると、アセットバンドルはUnityEngine.AssetBundle
オブジェクトとして利用できます。UnityEngine.AssetBundle
オブジェクトのコピーは 1 つだけ作成されます。これにより、ランタイムメモリの割り当てと、アセットバンドルの読み込みによるメモリへの影響が大幅に軽減されます。また、完全にダウンロードされていないときにアセットバンドルを部分的に使用することができます。ですから、アセットをストリーミングすることができます。
すべてのダウンロードと解凍はワーカースレッドで行われます。
アセットバンドルは、DownloadHandlerAssetBundle
オブジェクトをとおしてダウンロードされます。このオブジェクトには、アセットバンドルを取得する特別な assetBundle
プロパティーがあります。
アセットバンドルシステムの仕組みにより、すべてのアセットバンドルには関連付けられたアドレスが必要です。一般的には、これはアセットバンドルが位置する名目上の URL (リダイレクト前のURL ) です。ほとんどの場合、UnityWebRequest に渡したのと同じ URL を渡す必要があります。高レベル API (HLAPI) を使用する場合、これは本人の判断で行ってください。
using UnityEngine;
using System.Collections;
class MyBehaviour: public MonoBehaviour {
void Start() {
StartCoroutine(GetAssetBundle());
}
IEnumerator GetAssetBundle() {
UnityWebRequest www = new UnityWebRequest("http://www.my-server.com");
DownloadHandlerAssetBundle handler = new DownloadHandlerAssetBundle(www.url);
www.downloadHandler = handler;
yield return www.Send();
if(www.isError) {
Debug.Log(www.error);
}
else {
// Extracts AssetBundle
AssetBundle bundle = handler.assetBundle;
}
}
}
ダウンロードしたデータの処理を完全に制御する必要があるユーザのために、Unity はDownloadHandlerScript
クラスを提供します。
デフォルトでは、このクラスのインスタンスは何も行いません。ただし、DownloadHandlerScript
から独自のクラスを派生させる場合、特定の関数をオーバーライドして、ネットワークからデータが到着するときコールバックを受け取るためにその関数を使用します。
注意 実際のダウンロードはワーカースレッド上で行われますが、すべての DownloadHandlerScript
コールバックはメインスレッド上で動作します。 これらのコールバック中に負荷の高い計算操作を行なわないでください。
protected void ReceiveContentLength(long contentLength);
この関数は、Content Length ヘッダーが受信されたときに呼び出されます。 UnityWebRequest の処理中にサーバーが 1つ以上のリダイレクト応答を送信すると、このコールバックは複数回発生することがあります。
protected void OnContentComplete();
この関数は UnityWebRequest がサーバーからすべてのデータを完全にダウンロードし、それを ReceiveData コールバックに転送したときに呼び出されます。
protected bool ReceiveData(byte[] data, long dataLength);
この関数は、リモートサーバーからデータを受領した後に、フレームごとに 1 回呼び出されます。 data
引数には、リモートサーバーから受信した生のバイトが含まれます。また、 dataLength
はデータ配列内の新しいデータの長さを示します。
事前に割り当てられたデータバッファを使用しない場合、システムはこのコールバックを呼び出すたびに新しいバイト配列を作成し、dataLength
は常に data.Length
と等しくなります。 事前に割り当てられたデータバッファを使用する場合は、データバッファが再利用され、更新されたバイト数を見つけるために dataLength
を使用する必要があります。
この関数には、true または false のいずれかの戻り値が必要です。false を返すと、システムは直ちに UnityWebRequest を中止します。true を返すと、処理は正常に続行されます。
もっと上級レベルの Unity ユーザーの多くは、ガベージコレクションのために CPU スパイクを減らすことを気にかけています。これらのユーザのために、UnityWebRequest システムは、ダウンロードされたデータを DownloadHandlerScript のReceiveData
コールバックに配信するために使用されるマネージドのコードのバイト配列の事前割り当てを許可します。
この関数を使用すると、DownloadHandlerScript 派生クラスを使用してダウンロードしたデータを取得するときに、マネージドのコードのメモリ割り当てを完全に排除します。
DownloadHandlerScript
をあらかじめ割り当てられたマネージバッファで動作させるには、バイト配列を DownloadHandlerScript
のコンストラクタに渡します。
注意 バイト配列のサイズは、各フレームで ReceiveData コールバックに渡されるデータ量を制限します。データがゆっくりと、多くのフレームにわたって到着した場合、バイト配列が小さすぎる可能性があります。
using UnityEngine;
using System.Collections;
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 ReceiveContentLength(int contentLength) {
Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveContentLength - length {0}", contentLength));
}
}