Unity中使用LoadImage加载图片卡顿,如何实现无阻塞加载?
Unity加载本地图片避免卡顿的最佳方案
你的代码卡顿的核心原因是所有操作都在主线程同步执行:File.ReadAllBytes会阻塞主线程读取文件,texture.LoadImage也会在主线程处理图片解码,大图片必然导致卡顿。以下是几种可靠的异步加载方案:
方案一:使用UnityWebRequestTexture(官方推荐,简单高效)
UnityWebRequestTexture内部会在后台线程处理文件读取和纹理解码,完全不会阻塞主线程,是处理本地/远程图片异步加载的首选方式。
// 异步加载本地图片的协程方法 public IEnumerator LoadTextureAsync(string localFilePath, Action<Texture2D> onLoadComplete) { // 把本地路径转换为UnityWebRequest支持的file://协议格式 string requestUrl = "file://" + localFilePath; // 处理Windows系统下的路径分隔符 requestUrl = requestUrl.Replace("\\", "/"); using (UnityWebRequest webRequest = UnityWebRequestTexture.GetTexture(requestUrl)) { // 发送异步请求,等待完成 yield return webRequest.SendWebRequest(); if (webRequest.result == UnityWebRequest.Result.Success) { // 获取加载完成的纹理 Texture2D loadedTexture = DownloadHandlerTexture.GetContent(webRequest); onLoadComplete?.Invoke(loadedTexture); } else { Debug.LogError($"图片加载失败: {webRequest.error}"); onLoadComplete?.Invoke(null); } } }
调用示例
// 在需要加载图片的地方启动协程 StartCoroutine(LoadTextureAsync("你的本地图片路径", (texture) => { if (texture != null) { // 在这里使用纹理,比如赋值给UI的RawImage yourRawImage.texture = texture; } }));
方案二:后台线程读文件+主线程加载纹理
如果需要更精细控制流程,可以把文件读取的耗时操作放到后台线程,仅在主线程执行纹理解码(因为Unity的Texture操作必须在主线程)。
// 后台加载图片的方法 public void LoadTextureInBackground(string localFilePath, Action<Texture2D> onLoadComplete) { // 把文件读取任务放到线程池 System.Threading.ThreadPool.QueueUserWorkItem(_ => { byte[] imageBytes = null; try { imageBytes = File.ReadAllBytes(localFilePath); } catch (Exception ex) { Debug.LogError($"读取文件失败: {ex.Message}"); } // 回到主线程处理纹理加载 UnityMainThreadDispatcher.Instance.Enqueue(() => { if (imageBytes == null) { onLoadComplete?.Invoke(null); return; } Texture2D texture = new Texture2D(2, 2, TextureFormat.RGBA32, false); if (texture.LoadImage(imageBytes)) { onLoadComplete?.Invoke(texture); } else { Debug.LogError("纹理解码失败"); Destroy(texture); onLoadComplete?.Invoke(null); } }); }); }
配套主线程调度器
需要一个简单的工具类来把回调切回主线程:
public class UnityMainThreadDispatcher : MonoBehaviour { public static UnityMainThreadDispatcher Instance { get; private set; } private readonly Queue<Action> _pendingActions = new Queue<Action>(); private readonly object _lockObj = new object(); private void Awake() { if (Instance == null) { Instance = this; DontDestroyOnLoad(gameObject); } else { Destroy(gameObject); } } private void Update() { lock (_lockObj) { while (_pendingActions.Count > 0) { _pendingActions.Dequeue()(); } } } public void Enqueue(Action action) { lock (_lockObj) { _pendingActions.Enqueue(action); } } }
方案三:Addressables资源系统(大型项目首选)
如果是资源量较大的项目,推荐使用Unity官方的Addressables系统,它不仅支持异步加载,还能统一管理资源的缓存、卸载、更新,大幅简化资源管理流程。
加载示例
using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; public async void LoadTextureWithAddressables(string assetKey) { try { AsyncOperationHandle<Texture2D> loadHandle = Addressables.LoadAssetAsync<Texture2D>(assetKey); Texture2D texture = await loadHandle.Task; // 使用纹理 yourRawImage.texture = texture; // 不需要时可以释放资源(可选) // Addressables.Release(loadHandle); } catch (Exception ex) { Debug.LogError($"Addressables加载失败: {ex.Message}"); } }
最佳实践总结
- 中小图片或快速迭代场景:优先用UnityWebRequestTexture,代码简单且无需额外依赖
- 需要精细控制线程流程:用后台线程读文件+主线程加载纹理的组合
- 大型项目或需要复杂资源管理:用Addressables统一管理资源
内容的提问来源于stack exchange,提问作者Esa Nuriana
相关产品推荐
相关产品推荐

