You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity安卓端如何实现从内部存储无缝加载图片?性能优化求助

Unity安卓拼图游戏本地图片加载优化方案

现有代码核心问题

  • 用UnityWebRequest加载本地存储文件,额外引入了网络请求模块的开销,加载速度慢
  • 无内存缓存,滚动视图中同一张图反复销毁、重复从本地读取解码,IO开销冗余
  • 未做纹理尺寸适配,原始高清图直接加载进内存,安卓设备内存阈值低,极易出现内存不足加载失败的问题
  • 频繁调用GetComponent获取组件,无提前缓存
  • 存储的是原始JPG/PNG资源,每次加载都要做全量解码,CPU开销高

具体优化措施

1. 替换本地文件加载逻辑

直接删除UnityWebRequest加载本地文件的逻辑,改用File.ReadAllBytes+Texture2D.LoadImage读取本地文件,加载速度至少提升30%以上。

2. 新增LRU内存缓存层

全局维护一个最多存储20~30张最近使用纹理的LRU缓存,滚动时显示过的图片不用重复读本地,直接从内存取,同时缓存满了自动释放最久未使用的纹理,避免内存溢出。

3. 加载时强制适配显示尺寸

根据你的关卡缩略图实际显示尺寸(比如256*256),加载纹理的时候强制缩小到对应尺寸,内存占用可降低到原来的1/16甚至更低,解码速度也会大幅提升。

4. 组件提前缓存

在Awake阶段就提前获取当前对象的RawImage组件,不要每次加载图片的时候都调用GetComponent。

5. 分帧加载控制

限制同一时间加载的图片协程数量,最多同时跑2~3个加载协程,避免一帧内大量解码操作造成卡顿。

优化后示例代码

// 全局LRU缓存示例,可放在单例类里,简单实现即可无需引入第三方库
public static LRUCache<string, Texture2D> imageCache = new LRUCache<string, Texture2D>(30);
private RawImage _rawImage;

private void Awake()
{
    _rawImage = GetComponent<RawImage>();
}

public IEnumerator DownloadOrLoadImage(string link, string dirName, int index = -1)
{
    if (!loadFromResources)
    {
        int startPos = link.LastIndexOf("https://drive.google.com/file/d/") + "https://drive.google.com/file/d/".Length;
        int length = link.IndexOf("/view?usp=sharing") - startPos;
        if (length >= 1)
        {
            string ID = link.Substring(startPos, length);
            string cachePath = Application.persistentDataPath + "/.cache/" + ID;
            
            // 先查内存缓存
            if (imageCache.TryGet(ID, out Texture2D cachedTex))
            {
                _rawImage.texture = cachedTex;
                isImageDownloaded = true;
                if (index != -1 && index == LevelMenuLoader.instance.totalJsonCount)
                {
                    LevelMenuLoader.instance.AfterMenuDownloadSequence();
                }
                yield break;
            }

            if (File.Exists(cachePath))
            {
                if (index != -1 && index == LevelMenuLoader.instance.totalJsonCount)
                {
                    LevelMenuLoader.instance.AfterMenuDownloadSequence();
                }
                print("Loading from the device");
                
                // 同步读字节,等一帧分散压力避免卡顿
                byte[] bytes = File.ReadAllBytes(cachePath);
                yield return null;
                
                if (bytes.Length > 1)
                {
                    Texture2D tex = new Texture2D(2, 2, TextureFormat.RGB24, false);
                    tex.LoadImage(bytes);
                    // 按需缩放到目标显示尺寸,比如缩略图需要256*256就填256
                    // ScaleTexture(tex, 256, 256);
                    _rawImage.texture = tex;
                    // 加入内存缓存
                    imageCache.Put(ID, tex);
                    isImageDownloaded = true;
                }
            }
            else
            {
                LevelMenuLoader.instance.AfterMenuDownloadSequence();
                print("Downloading from the web");
                using (UnityWebRequest request = UnityWebRequestTexture.GetTexture(link))
                {
                    yield return request.SendWebRequest();
                    if (request.result != UnityWebRequest.Result.Success)
                    {
                        Debug.Log(request.error);
                    }
                    else
                    {
                        Texture2D downloadedTex = ((DownloadHandlerTexture)request.downloadHandler).texture;
                        byte[] bytes = ((DownloadHandlerTexture)request.downloadHandler).data;
                        if (bytes.Length > 1)
                        {
                            // 下载后先缩放到目标尺寸再存储,减少本地文件大小和后续加载开销
                            // ScaleTexture(downloadedTex, 256, 256);
                            // byte[] compressedBytes = downloadedTex.EncodeToJPG(80);
                            File.WriteAllBytes(cachePath, bytes);
                            _rawImage.texture = downloadedTex;
                            imageCache.Put(ID, downloadedTex);
                            isImageDownloaded = true;
                        }
                        request.downloadHandler.Dispose();
                    }
                }
            }
        }
    }
    else
    {
        string resPath = "Levels/" + dirName + "/" + GetComponent<LevelInformation>().m_LevelID;
        _rawImage.texture = Resources.Load<Texture>(resPath);
    }
}

// 纹理缩放辅助方法
private void ScaleTexture(Texture2D source, int targetWidth, int targetHeight)
{
    RenderTexture rt = RenderTexture.GetTemporary(targetWidth, targetHeight);
    Graphics.Blit(source, rt);
    RenderTexture.active = rt;
    source.Reinitialize(targetWidth, targetHeight);
    source.ReadPixels(new Rect(0, 0, targetWidth, targetHeight), 0, 0);
    source.Apply();
    RenderTexture.ReleaseTemporary(rt);
    RenderTexture.active = null;
}

内容的提问来源于stack exchange,提问作者Bhavin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 01:24:05