需要载入大量图片到Image并显示,基本方法有2种,用WWW或者c#的FileStream。考虑到协程,异步,以及把代码统一写或者分开写,衍生出5、6种方法。
job system只能处理值类型,帮不上忙。ecs也主要集中在处理update里面的内容,似乎也不使用。还考虑过多线程,这里不是很确定。unity多线程过程中,子线程不能使用unity的api,就只能用c#把文件读取过程加速,对多线程不熟,就放弃了。
结论
会出现3种效果,在使用FileStream异步,在统一的地方写代码适应毕竟广。
测试方法,加载102张512*512分辨率的图片,显示成一个图片下拉列表,样子如下
测试视频地址(好像没啥意义):https://www.bilibili.com/video/av32416457/
方法一、统一调用WWW协程
GuiController.CS
/// <summary>
/// 统一处理WWW协程载入
/// </summary>
public void UniteCoroutineWWW()
{
//从json获取图片地址信息并转为对象数组
MediaText[] mts = JsonConvert.DeserializeObject<MediaText[]>(ifJson.text);
scrollView.SetActive(true);
//遍历对象数组
foreach (MediaText mt in mts)
{
//实列化游戏对象
Transform tf = Instantiate(prefab, content);
tf.GetChild(1).GetComponent<Text>().text = mt.Name;
tf.GetChild(2).GetComponent<Text>().text = mt.Description;
Image image = tf.GetChild(0).GetComponent<Image>();
//调用协程
StartCoroutine(LoadByWWW(mt.Icon, image));
}
}
/// <summary>
/// WWW协程载入图片
/// </summary>
/// <param name="path">图片地址</param>
/// <param name="image">Image对象</param>
/// <returns></returns>
IEnumerator LoadByWWW(string path, Image image)
{
path = @"file://"+fileRoot + path;
using (WWW www = new WWW(path))
{
yield return www;
if (www.isDone && www.error == null)
{
image.sprite = Sprite.Create(www.texture, new Rect(0, 0, 512f, 512f), new Vector2(0.5f, 0.5f));
}
else
{
Debug.Log(www.error);
}
}
}
载入情况:先把所有Image初始完成后,统一载入了图片。
cpu占用信息
方法二、统一调用WWW载入,不使用协程
GuiController.CS
/// <summary>
/// 统一调用WWW,不使用协程
/// </summary>
public void UniteSynchronizeWWW()
{
string path = @"file://"+fileRoot;
MediaText[] mts = JsonConvert.DeserializeObject<MediaText[]>(ifJson.text);
scrollView.SetActive(true);
foreach (MediaText mt in mts)
{
Transform tf = Instantiate(prefab, content);
tf.GetChild(1).GetComponent<Text>().text = mt.Name;
tf.GetChild(2).GetComponent<Text>().text = mt.Description;
Image image = tf.GetChild(0).GetComponent<Image>();
using (WWW www = new WWW(path+mt.Icon))
{
while (!www.isDone)
{
if (www.error == null)
{
image.sprite = Sprite.Create(www.texture, new Rect(0, 0, 512f, 512f), new Vector2(0.5f, 0.5f));
}
else
{
Debug.Log(www.error);
}
}
}
}
}
载入情况,会等所有内容准备好后一并显示
cpu占用信息
方法三、统一FileStream异步
GuiController.CS
/// <summary>
/// 异步载入图片
/// </summary>
/// <param name="path">路径</param>
/// <param name="image">Image对象</param>
/// <returns></returns>
async Task LoadByFSAsync(string path, Image image)
{
path = fileRoot + path;
byte[] result;
using (FileStream SourceStream = File.Open(path, FileMode.Open))
{
result = new byte[SourceStream.Length];
await SourceStream.ReadAsync(result, 0, (int)SourceStream.Length);
}
Texture2D tx = new Texture2D(512, 512);
tx.LoadImage(result);
image.sprite = Sprite.Create(tx, new Rect(0, 0, 512f, 512f), new Vector2(0.5f, 0.5f));
}
/// <summary>
/// 统一异步载入
/// </summary>
public async void UniteFSAsync()
{
MediaText[] mts = JsonConvert.DeserializeObject<MediaText[]>(ifJson.text);
scrollView.SetActive(true);
foreach (MediaText mt in mts)
{
Transform tf = Instantiate(prefab, content);
tf.GetChild(1).GetComponent<Text>().text = mt.Name;
tf.GetChild(2).GetComponent<Text>().text = mt.Description;
Image image = tf.GetChild(0).GetComponent<Image>();
await LoadByFSAsync(mt.Icon, image);
}
}
载入情况:会顺序将对象实例化并载入图片
cpu占用
方法四、由游戏对象自己用WWW协程载入
GuiController.CS
/// <summary>
/// 由游戏对象自己载入图片
/// </summary>
public void SelfLoad()
{
MediaText[] mts = JsonConvert.DeserializeObject<MediaText[]>(ifJson.text);
scrollView.SetActive(true);
foreach (MediaText mt in mts)
{
Transform tf = Instantiate(prefab, content);
tf.GetChild(1).GetComponent<Text>().text = mt.Name;
tf.GetChild(2).GetComponent<Text>().text = mt.Description;
LoadImage loadImage = tf.GetComponent<LoadImage>();
loadImage.path = fileRoot + mt.Icon;
//LoadImageDestory lid = tf.GetComponent<LoadImageDestory>();
//lid.path = fileRoot + mt.Icon;
}
}
LoadImage.CS
void Start () {
image = transform.GetChild(0).GetComponent<Image>();
StartCoroutine(LoadByWWW(path, image));
//LoadByFSAsync(path, image);
}
/// <summary>
/// 用WWW协程载入图片
/// </summary>
/// <param name="path"></param>
/// <param name="image"></param>
/// <returns></returns>
IEnumerator LoadByWWW(string path, Image image)
{
path = @"file://" + path;
using (WWW www = new WWW(path))
{
yield return www;
if (www.isDone && www.error == null)
{
image.sprite = Sprite.Create(www.texture, new Rect(0, 0, 512f, 512f), new Vector2(0.5f, 0.5f));
}
else
{
Debug.Log(www.error);
}
}
}
载入情况:先把所有Image初始完成后,统一载入了图片。
cpu占用
方法五,由游戏对象自己用FileStream异步载入
GuiController.CS
/// <summary>
/// 由游戏对象自己载入图片
/// </summary>
public void SelfLoad()
{
MediaText[] mts = JsonConvert.DeserializeObject<MediaText[]>(ifJson.text);
scrollView.SetActive(true);
foreach (MediaText mt in mts)
{
Transform tf = Instantiate(prefab, content);
tf.GetChild(1).GetComponent<Text>().text = mt.Name;
tf.GetChild(2).GetComponent<Text>().text = mt.Description;
LoadImage loadImage = tf.GetComponent<LoadImage>();
loadImage.path = fileRoot + mt.Icon;
//LoadImageDestory lid = tf.GetComponent<LoadImageDestory>();
//lid.path = fileRoot + mt.Icon;
}
}
LoadImage.CS
void Start () {
image = transform.GetChild(0).GetComponent<Image>();
//StartCoroutine(LoadByWWW(path, image));
LoadByFSAsync(path, image);
}
async Task LoadByFSAsync(string path, Image image)
{
byte[] result;
using (FileStream SourceStream = File.Open(path, FileMode.Open))
{
result = new byte[SourceStream.Length];
await SourceStream.ReadAsync(result, 0, (int)SourceStream.Length);
}
Texture2D tx = new Texture2D(512, 512);
tx.LoadImage(result);
image.sprite = Sprite.Create(tx, new Rect(0, 0, 512f, 512f), new Vector2(0.5f, 0.5f));
}
载入情况,会等所有内容准备好后一并显示
cpu占用信息