从持久性数据路径加载图像



我正在制作一个Android应用程序,一开始应该从MySQL数据库加载数据,并从服务器加载一些图像。之后,用户将在外面,因此应用程序将脱机工作。

我编写了代码来保存所有数据库数据(它有效)和来自服务器的图像到ApplicationPersistenceDataPath(不起作用)。我已经在寻找我应该如何做到这一点。我拥有的代码不会引发任何错误。但是,当我尝试在应用程序上显示它时,图像是空白的。那时我查看了存储图像的文件夹,但我无法打开它们。

这是我保存图像的方法:

IEnumerator loadBgImage(string url, string file_name)
{
using (UnityWebRequest www = UnityWebRequest.Get(url))
{
yield return www.Send();
if (www.isNetworkError || www.isHttpError)
{
print("erro");
}
else
{
string savePath = string.Format("{0}/{1}", Application.persistentDataPath, file_name);
if (!File.Exists(savePath))
{
System.IO.File.WriteAllText(savePath, www.downloadHandler.text);
}
}
}
}

这是在图像中显示图像文件的代码:

string path = Application.persistentDataPath + "/" + nomeImagem;
imagem.GetComponent<SpriteRenderer>().sprite = LoadSprite(path);

这是称为的方法:

private Sprite LoadSprite(string path)
{
if (string.IsNullOrEmpty(path)) return null;
if (System.IO.File.Exists(path))
{            
byte[] bytes = File.ReadAllBytes(path);
Texture2D texture = new Texture2D(900, 900, TextureFormat.RGB24, false);
texture.filterMode = FilterMode.Trilinear;
texture.LoadImage(bytes);
Sprite sprite = Sprite.Create(texture, new Rect(0, 0, 8, 8), new Vector2(0.5f, 0.0f), 1.0f);
}
return null;
}

我真的需要先保存图像,然后离线显示。有人可以告诉我我做错了什么吗?

更新按照@derHugo答案的建议进行操作后,这是我保存图像的代码:

IEnumerator loadBgImage(string url, string file_name)
{
using (UnityWebRequest www = UnityWebRequest.Get(url))
{
yield return www.Send();
if (www.isNetworkError || www.isHttpError)
{
print("erro");
}
else
{
var savePath = Path.Combine(Application.persistentDataPath, file_name);
var data = www.downloadHandler.data;
using (var fs = new FileStream(savePath, FileMode.Create, FileAccess.Write))
{
fs.Write(data, 0, data.Length);
}
}
}
}

它可以工作,但是在运行应用程序时我仍然看不到图像。在显示精灵的方法中,我添加了创建的精灵的返回。

第二次更新

我再次遵循@derHugo的建议,我使用原始图像而不是图像。它现在可以在Unity编辑器和Android设备上工作。这是我使用的方法:

private void LoadSprite(string path)
{
if (string.IsNullOrEmpty(path)) print("erro");
if (System.IO.File.Exists(path))
{
byte[] bytes = File.ReadAllBytes(path);
Texture2D texture = new Texture2D(900, 900, TextureFormat.RGB24, false);
texture.filterMode = FilterMode.Trilinear;
texture.LoadImage(bytes);
imagem.texture = texture;
}
}

一般来说,你应该使用Path.Combine

var path = Path.Combine(Application.persistentDataPath, FileName);

改为系统路径!可能是您的目标设备根本不理解/路径分隔符。


如果文件已经存在,也可以写入(也许是更新的版本?无论如何,您已经下载了它),或者如果它已经存在以节省带宽,您甚至不应该开始下载。


我也认为WriteAllText不是二进制图像数据的正确解决方案,因为www.downloadHandler.text已经

解释为 UTF8 字符串

因此,由于图像很可能有一些无法在 UTF8 字符串中表示的字节,因此您在此处会得到损坏的数据!

你宁愿直接使用

www.downloadHandler.data

它返回原始byte[]而不是例如File.WriteAllBytes(仅在 UWP 上)或用于将该byte[]写入文件的适当FileStream。类似的东西

var data = www.downloadHandler.data;
File.WriteAllBytes(path, data);

var data = www.downloadHandler.data;
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
{
fs.Write(data, 0, data.Length);
}

比场景中的白色图像通常意味着精灵null

如果没有错别字,那么您LoadSprite总是返回null.您忘记返回创建的sprite

private Sprite LoadSprite(string path)
{
if (string.IsNullOrEmpty(path)) return null;
if (System.IO.File.Exists(path))
{            
byte[] bytes = File.ReadAllBytes(path);
Texture2D texture = new Texture2D(900, 900, TextureFormat.RGB24, false);
texture.filterMode = FilterMode.Trilinear;
texture.LoadImage(bytes);
Sprite sprite = Sprite.Create(texture, new Rect(0, 0, 8, 8), new Vector2(0.5f, 0.0f), 1.0f);
// You should return the sprite here!
return sprite;
}
return null;
}

但是请注意,实际上也UnityWebRequestTexture加载本地图像的更好方法。它还采用本地文件路径作为 URL 和

与下载原始字节并在脚本中手动创建纹理相比,使用此类可显著减少内存重新分配。此外,纹理转换将在工作线程上执行。

但也

仅支持 JPG 和 PNG 格式。

但我想这应该不是问题,因为您到目前为止使用LoadImage是相同的限制的基础。

但是,这将是异步的,因此您必须等待纹理才能创建精灵。因此,与其重新调整Sprite,我实际上宁愿传入相应Image组件的引用并直接替换其sprite。类似的东西

private IEnumerator LoadLocalTexture(string path, Image receivingImage)
{
UnityWebRequest www = UnityWebRequestTexture.GetTexture(path);
yield return www.SendWebRequest();
if(www.isNetworkError || www.isHttpError) 
{
Debug.Log(www.error);
}
else 
{
var texture = ((DownloadHandlerTexture)www.downloadHandler).texture;
var sprite = Sprite.Create(texture, new Rect(0, 0, 8, 8), new Vector2(0.5f, 0.0f), 1.0f);
receivingImage.sprite = sprite;
}
}

如果您不必实际使用Sprites我总是建议宁愿使用RawImage组件,而不是可以直接使用Texture2D的组件!而不是做类似的事情

private IEnumerator LoadLocalTexture(string path, RawImage receivingImage)
{
UnityWebRequest www = UnityWebRequestTexture.GetTexture(path);
yield return www.SendWebRequest();
if(www.isNetworkError || www.isHttpError) 
{
Debug.Log(www.error);
}
else 
{
var texture = ((DownloadHandlerTexture)www.downloadHandler).texture;
receivingImage.texture = texture;
}
}

但也

注意 :请记住,使用 RawImage 会在存在每个 RawImage 时创建一个额外的绘制调用,因此最好仅将其用于背景或临时可见图形。

最新更新