05-05-YooAsset源码-Unity资源加载与Provider体系
2026/8/4 6:59:57 网站建设 项目流程

源码-资源提供者(Provider 体系)

篇章:05-源码深度-运行时核心模块
阅读时间:约 30 分钟
前置知识:了解寻址系统


一、引言

本章将深入解析 YooAsset 资源提供者(Provider 体系)的源码实现。Provider 是 YooAsset 资源加载的核心,封装了不同类型资源的加载逻辑。YooAsset 提供了多种 Provider 类型,包括 AssetProvider、SceneProvider、ComponentProvider 等。

Provider 体系的设计目标是提供灵活、可扩展的资源加载能力。本章将从源码层面深入解析 Provider 体系的设计和实现。


二、Provider 概述

2.1 Provider 的概念

Provider 是 YooAsset 中负责加载单个资源的核心组件:

Provider 的定义

Provider 是一个抽象类,封装了资源加载的所有逻辑。每个 Provider 对应一个资源的加载。

Provider 的特点

  • 单一职责:每个 Provider 只负责一个资源
  • 状态管理:Provider 维护资源加载的状态
  • 引用计数:Provider 内置引用计数管理
  • 异步加载:Provider 支持异步加载资源

Provider 的作用

  • 接收资源加载请求
  • 创建和加载 Bundle
  • 从 Bundle 中加载资源
  • 管理资源生命周期

2.2 Provider 状态机

Provider 内部维护了一个状态机:

Provider 状态机 ├── None:初始状态 ├── Loading:加载中 ├── Loaded:已加载 ├── Releasing:释放中 └── Destroyed:已销毁

None 详解

None 是 Provider 的初始状态,Provider 创建后即进入 None 状态。

Loading 详解

Loading 是 Provider 的加载中状态。Provide 方法被调用后进入 Loading 状态。

Loaded 详解

Loaded 是 Provider 的已加载状态。资源加载完成后进入 Loaded 状态。

Releasing 详解

Releasing 是 Provider 的释放中状态。UnProvide 方法被调用后进入 Releasing 状态。

Destroyed 详解

Destroyed 是 Provider 的已销毁状态。资源销毁后进入 Destroyed 状态。

2.3 Provider 状态详解

public enum EProviderStatus { None = 0, // 初始状态 Loading = 1, // 加载中 Loaded = 2, // 已加载 Failed = 3, // 加载失败 Destroyed = 4, // 已销毁 }

状态转换详解

  • None → Loading:调用 Provide 方法
  • Loading → Loaded:资源加载成功
  • Loading → Failed:资源加载失败
  • Loaded/Failed → Destroyed:调用 Destroy 方法

2.4 Provider 创建

public abstract class ProviderBase { public string Location { get; } public EProviderStatus Status { get; protected set; } public float Progress { get; protected set; } public object AssetObject { get; protected set; } public int RefCount { get; protected set; } public abstract void Provide(); public abstract void UnProvide(); public abstract void Update(); }

Location 详解

Location 是 Provider 加载的资源地址。

Status 详解

Status 是 Provider 的当前状态。

Progress 详解

Progress 是 Provider 的加载进度。

AssetObject 详解

AssetObject 是 Provider 加载的资源对象。

RefCount 详解

RefCount 是 Provider 的引用计数。


三、Provider 创建/获取

3.1 Provider 的创建

Provider 的创建由 ResourceManager 负责:

public class ResourceManager { public AssetProvider CreateAssetProvider(string location, Type assetType) { AssetProvider provider = new AssetProvider(this, location, assetType); return provider; } }

Provider 实例化详解

ResourceManager 根据资源的类型创建对应的 Provider。

Provider 参数详解

创建 Provider 时需要传入 ResourceManager、location、assetType 等参数。

3.2 Provider 的获取

public class ResourceManager { private Dictionary<string, ProviderBase> _providerCache = new Dictionary<string, ProviderBase>(); public ProviderBase GetOrCreateProvider(string location, Type assetType) { string key = $"{location}_{assetType.Name}"; if (_providerCache.TryGetValue(key, out var provider)) { provider.IncreaseRefCount(); return provider; } provider = CreateAssetProvider(location, assetType); _providerCache[key] = provider; provider.IncreaseRefCount(); return provider; } }

Provider 复用详解

GetOrCreateProvider 方法会先在缓存中查找已存在的 Provider。如果存在则复用,否则创建新的。

引用计数增加详解

每次获取 Provider 时,引用计数加 1。

3.3 Provider 的销毁

public class ResourceManager { public void DestroyProvider(ProviderBase provider) { string key = provider.Location; _providerCache.Remove(key); provider.Destroy(); } }

Provider 销毁详解

当 Provider 的引用计数为 0 时,会从缓存中移除并销毁。


四、Provider 加载/卸载

4.1 加载流程

Provider 的加载流程如下:

Provider 加载流程 1. 接收加载请求 2. 增加引用计数 3. 启动加载流程 a. 创建 BundleLoader b. 加载 Bundle c. 加载依赖的 Bundle d. 从 Bundle 中加载资源 4. 加载完成 5. 触发回调

接收加载请求详解

用户调用 LoadAssetAsync 时,ResourceManager 会创建或复用 Provider。

增加引用计数详解

每次加载请求会增加 Provider 的引用计数。

启动加载流程详解

Provide 方法启动加载流程。

Bundle 加载详解

Provider 创建 BundleLoader 加载 Bundle。

资源加载详解

从 Bundle 中加载资源。

4.2 加载实现

public class AssetProvider : ProviderBase { private BundleLoader _bundleLoader; private List<BundleLoader> _dependLoaders; private AssetBundleRequest _request; public override void Provide() { Status = EProviderStatus.Loading; Progress = 0; // 1. 获取 AssetInfo var assetInfo = Package.GetAssetInfo(Location); if (assetInfo == null) { Status = EProviderStatus.Failed; Error = "AssetInfo not found"; return; } // 2. 加载依赖 Bundle _dependLoaders = new List<BundleLoader>(); foreach (var depBundleID in assetInfo.DependIDs) { var depBundle = Package.GetBundleInfo(depBundleID); var loader = Package.ResourceManager.LoadBundle(depBundle); _dependLoaders.Add(loader); } // 3. 加载主 Bundle var mainBundle = Package.GetBundleInfo(assetInfo.BundleID); _bundleLoader = Package.ResourceManager.LoadBundle(mainBundle); } public override void Update() { if (Status != EProviderStatus.Loading) return; // 计算进度 float total = _dependLoaders.Count + 1; float current = 0; foreach (var loader in _dependLoaders) { if (loader.IsDone) current++; } if (_bundleLoader.IsDone) current++; Progress = current / total; // 检查是否完成 if (Progress < 1) return; // 加载资源 _request = _bundleLoader.AssetBundle.LoadAssetAsync(AssetInfo.AssetPath, AssetType); } }

加载依赖 Bundle 详解

加载资源前,先加载所有依赖的 Bundle。

加载主 Bundle 详解

加载资源所属的主 Bundle。

进度计算详解

进度 = 已加载的 Bundle 数 / 总 Bundle 数。

资源加载详解

所有 Bundle 加载完成后,从主 Bundle 中加载资源。

4.3 卸载流程

Provider 的卸载流程:

Provider 卸载流程 1. 接收卸载请求 2. 减少引用计数 3. 引用计数为 0 时启动销毁 4. 释放资源 5. 销毁 Bundle 引用 6. 销毁 Provider

接收卸载请求详解

用户调用 UnloadAsset 时,ResourceManager 减少 Provider 的引用计数。

引用计数减少详解

每次卸载请求会减少 Provider 的引用计数。

销毁触发详解

引用计数为 0 时,Provider 启动销毁流程。

4.4 卸载实现

public class AssetProvider : ProviderBase { public override void UnProvide() { DecreaseRefCount(); if (RefCount > 0) return; Status = EProviderStatus.Destroyed; // 释放资源 if (AssetObject != null) { if (AssetObject is GameObject) { // 释放 GameObject 资源 } Resources.UnloadAsset(AssetObject); } // 减少 Bundle 引用 Package.ResourceManager.UnloadBundle(_bundleLoader); foreach (var loader in _dependLoaders) { Package.ResourceManager.UnloadBundle(loader); } } }

资源释放详解

使用 Resources.UnloadAsset 释放资源。

Bundle 引用减少详解

减少 Bundle 的引用计数,引用为 0 时销毁 Bundle。


五、Provider 类型

5.1 AssetProvider

AssetProvider 是最常用的 Provider,用于加载普通资源:

public class AssetProvider : ProviderBase { public override void Provide(); public override void UnProvide(); public override void Update(); }

AssetProvider 的用途详解

加载 Prefab、Texture、Material、AudioClip 等普通资源。

AssetProvider 的实现详解

AssetProvider 继承自 ProviderBase,实现了 Provide、UnProvide、Update 方法。

5.2 SceneProvider

SceneProvider 用于加载场景资源:

public class SceneProvider : ProviderBase { public Scene Scene { get; } public AsyncOperation LoadSceneAsync(); public AsyncOperation UnloadSceneAsync(); }

SceneProvider 的用途详解

加载 Unity 场景。

SceneProvider 的特殊处理详解

SceneProvider 使用 Unity 的 SceneManager 加载场景,并管理场景的激活和卸载。

5.3 ComponentProvider

ComponentProvider 用于加载 Component 类型的资源:

public class ComponentProvider : ProviderBase { public GameObject Instance { get; } public T GetComponent<T>() where T : Component; }

ComponentProvider 的用途详解

加载 Prefab 并获取其中的 Component。

ComponentProvider 的实现详解

ComponentProvider 在 AssetProvider 的基础上,提供了 Component 获取的能力。

5.4 SubAssetsProvider

SubAssetsProvider 用于加载子资源:

public class SubAssetsProvider : ProviderBase { public Object[] SubAssets { get; } }

SubAssetsProvider 的用途详解

加载包含多个资源的 AssetBundle 中的特定子资源。

SubAssetsProvider 的应用场景详解

加载 Sprite Atlas 中的特定 Sprite、加载 AnimationClip 等。

5.5 RawFileProvider

RawFileProvider 用于加载原生文件:

public class RawFileProvider : ProviderBase { public byte[] RawData { get; } public string RawText { get; } }

RawFileProvider 的用途详解

加载原生格式的文件,如图片、文本等。

RawFileProvider 的实现详解

RawFileProvider 不会将资源转换为 Unity 对象,而是返回原始的字节数据。

5.6 BundleProvider

BundleProvider 用于加载整个 Bundle:

public class BundleProvider : ProviderBase { public AssetBundle AssetBundle { get; } }

BundleProvider 的用途详解

加载整个 AssetBundle,不加载具体的资源。

BundleProvider 的应用场景详解

需要手动管理 AssetBundle 内容的场景。


六、Provider 缓存机制

6.1 缓存的作用

Provider 缓存的作用:

避免重复创建

相同资源只创建一次 Provider,避免重复创建的开销。

复用 Provider

相同资源的加载请求复用同一个 Provider,避免重复加载。

提高性能

通过缓存减少内存分配和资源加载。

6.2 缓存的实现

public class ResourceManager { private Dictionary<string, ProviderBase> _providerCache = new Dictionary<string, ProviderBase>(); public ProviderBase GetProvider(string location, Type assetType) { string key = GenerateProviderKey(location, assetType); if (_providerCache.TryGetValue(key, out var provider)) { return provider; } return null; } public void CacheProvider(ProviderBase provider) { string key = GenerateProviderKey(provider.Location, provider.AssetType); _providerCache[key] = provider; } }

缓存 Key 生成详解

缓存 Key 由 location 和 assetType 组成,确保相同资源使用相同的 Key。

缓存查询详解

加载资源时先查询缓存,命中则复用,未命中则创建。

6.3 缓存的清理

public class ResourceManager { public void ClearUnusedProviders() { var unused = _providerCache.Where(p => p.Value.RefCount == 0).ToList(); foreach (var kvp in unused) { kvp.Value.Destroy(); _providerCache.Remove(kvp.Key); } } }

清理条件详解

引用计数为 0 的 Provider 是未使用的 Provider。

清理时机详解

可以在资源切换、关卡切换等时机调用清理方法。


七、总结

本章深入解析了 YooAsset 资源提供者(Provider 体系)的源码实现,包括:

  • Provider 概述:Provider 的概念、状态机、状态详解
  • Provider 创建/获取:Provider 的创建、获取、销毁
  • Provider 加载/卸载:加载流程、加载实现、卸载流程、卸载实现
  • Provider 类型:AssetProvider、SceneProvider、ComponentProvider、SubAssetsProvider、RawFileProvider、BundleProvider
  • Provider 缓存机制:缓存的作用、实现、清理

Provider 体系是 YooAsset 资源加载的核心,通过深入理解 Provider 体系,开发者可以更好地使用 YooAsset 的资源加载功能,并实现自定义的 Provider。


上一篇:寻址系统
下一篇:异步体系(OperationSystem)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询