第11章 Addressables架构解析

第11章 Addressables架构解析

Addressables系统架构图

Unity Addressables系统是一个复杂的资源管理系统,其架构设计遵循了模块化、可扩展和高性能的原则。整个系统由多个核心组件协同工作,形成了一个完整的资源加载和管理生态系统。

核心架构组件

Addressables系统的主要架构可以分为以下几个核心组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
┌─────────────────────────────────────────────────────────────┐
│ Addressables System │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
│ │ Addressables │ │ ResourceManager │ │ Resource │ │
│ │ API │ │ │ │ Locator │ │
│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
│ │ Address │ │ AsyncOperation │ │ Location │ │
│ │ Resolution │ │ Handles │ │ Data │ │
│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
│ │ Resource │ │ Provider │ │ Catalog │ │
│ │ Providers │ │ System │ │ Management │ │
│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘

架构层次详解

1. 应用层(Application Layer)

  • Addressables API: 提供给开发者的公共接口,包括LoadAssetAsync、Release等方法
  • 用户代码: 游戏逻辑代码,调用Addressables API进行资源管理

2. 服务层(Service Layer)

  • ResourceManager: 核心资源管理器,负责协调资源加载、缓存和释放
  • ResourceLocator: 资源定位器,根据地址查找资源位置信息
  • AsyncOperationHandles: 异步操作句柄系统,管理加载操作的生命周期

3. 执行层(Execution Layer)

  • Resource Providers: 资源提供者系统,实际执行资源加载操作
  • Location System: 位置管理系统,管理资源的物理位置信息
  • Catalog System: 目录管理系统,维护资源地址到位置的映射

系统架构特点

Addressables系统架构具有以下重要特点:

  1. 模块化设计: 各组件职责明确,便于维护和扩展
  2. 可扩展性: 支持自定义Provider和Location类型
  3. 异步优先: 所有资源操作都支持异步执行
  4. 缓存机制: 内置多级缓存系统
  5. 生命周期管理: 完整的资源引用计数和生命周期管理

核心模块关系(ResourceManager、ResourceLocator等)

ResourceManager详解

ResourceManager是Addressables系统的核心引擎,负责协调所有资源操作。它是一个单例模式的管理器,提供了统一的资源操作接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.ResourceManagement;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceLocations;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.ResourceManagement.Util;

public class ResourceManagerArchitecture : MonoBehaviour
{
[Header("ResourceManager配置")]
public int operationCacheSize = 1000;
public float timeoutDelay = 60f;
public bool enableDiagnostics = true;

private ResourceManager resourceManager;
private Dictionary<string, IResourceLocation> locationCache = new Dictionary<string, IResourceLocation>();
private List<AsyncOperationHandle> activeOperations = new List<AsyncOperationHandle>();

void Start()
{
InitializeResourceManager();
}

private void InitializeResourceManager()
{
// 创建ResourceManager实例
resourceManager = new ResourceManager();

// 配置ResourceManager参数
resourceManager.TimeoutDeltaTime = timeoutDelay;
resourceManager.DiagnosticLogging = enableDiagnostics;

Debug.Log("ResourceManager初始化完成");
}

/// <summary>
/// 模拟资源加载流程
/// </summary>
public AsyncOperationHandle<TObject> SimulateLoad<TObject>(string locationName) where TObject : class
{
// 1. 解析位置信息
IResourceLocation location = ResolveLocation(locationName);

if (location == null)
{
Debug.LogError($"无法解析位置: {locationName}");
return default(AsyncOperationHandle<TObject>);
}

// 2. 获取资源提供者
IResourceProvider provider = GetResourceProvider(location);

if (provider == null)
{
Debug.LogError($"无法找到资源提供者: {locationName}");
return default(AsyncOperationHandle<TObject>);
}

// 3. 创建异步操作句柄
var operation = resourceManager.CreateOperation<TObject>(provider, location, typeof(TObject));

// 4. 添加到活跃操作列表
activeOperations.Add(operation);

// 5. 开始执行操作
resourceManager.StartOperation(operation, location);

Debug.Log($"开始加载资源: {locationName}");

return operation;
}

private IResourceLocation ResolveLocation(string locationName)
{
// 模拟位置解析过程
// 在实际系统中,这会查询ResourceLocator

if (locationCache.ContainsKey(locationName))
{
return locationCache[locationName];
}

// 创建模拟位置
var mockLocation = new MockResourceLocation(locationName);
locationCache[locationName] = mockLocation;

return mockLocation;
}

private IResourceProvider GetResourceProvider(IResourceLocation location)
{
// 根据位置信息获取对应的资源提供者
string providerId = location.Provider;

// 在实际系统中,这里会从ProviderManager获取
// 简化实现,返回模拟提供者
return new MockResourceProvider(providerId);
}

/// <summary>
/// 获取ResourceManager统计信息
/// </summary>
public string GetResourceManagerStats()
{
var stats = new System.Text.StringBuilder();
stats.AppendLine("=== ResourceManager统计 ===");
stats.AppendLine($"活跃操作数: {activeOperations.Count}");
stats.AppendLine($"位置缓存数: {locationCache.Count}");
stats.AppendLine($"操作缓存大小: {operationCacheSize}");
stats.AppendLine($"超时延迟: {timeoutDelay}s");
stats.AppendLine($"诊断日志: {enableDiagnostics}");

return stats.ToString();
}

/// <summary>
/// 清理ResourceManager
/// </summary>
public void CleanupResourceManager()
{
// 释放所有活跃操作
foreach (var handle in activeOperations)
{
resourceManager.Release(handle);
}
activeOperations.Clear();

// 清空位置缓存
locationCache.Clear();

Debug.Log("ResourceManager清理完成");
}

void OnDestroy()
{
CleanupResourceManager();
}
}

/// <summary>
/// 模拟资源位置类
/// </summary>
[System.Serializable]
public class MockResourceLocation : IResourceLocation
{
public string InternalId { get; set; }
public string ProviderId { get; set; }
public IList<IResourceLocation> Dependencies { get; set; }
public object Data { get; set; }
public string PrimaryKey { get; set; }

public MockResourceLocation(string key)
{
PrimaryKey = key;
InternalId = key;
ProviderId = "MockProvider";
Dependencies = new List<IResourceLocation>();
}

public bool HasKey(string key)
{
return PrimaryKey == key;
}

public bool Matches(string key)
{
return PrimaryKey == key;
}

public T GetData<T>()
{
return (T)Data;
}
}

/// <summary>
/// 模拟资源提供者类
/// </summary>
public class MockResourceProvider : IResourceProvider
{
public string ProviderId { get; private set; }

public MockResourceProvider(string providerId)
{
ProviderId = providerId;
}

public void Provide(ProvideHandle provideHandle)
{
// 模拟资源提供过程
string locationName = provideHandle.Location.PrimaryKey;

// 模拟异步加载
System.Threading.Tasks.Task.Delay(100).ContinueWith(_ =>
{
// 加载完成,设置结果
provideHandle.Complete(locationName, true, null);
});
}

public void Release(IResourceLocation location, object asset)
{
// 模拟资源释放
Debug.Log($"释放资源: {location.PrimaryKey}");
}
}

ResourceLocator详解

ResourceLocator是Addressables系统中负责资源定位的核心组件,它维护了资源地址到位置信息的映射关系。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.ResourceManagement.ResourceLocations;

public class ResourceLocatorArchitecture : MonoBehaviour
{
[Header("ResourceLocator配置")]
public string locatorId = "DefaultLocator";
public int maxCacheSize = 1000;

private Dictionary<string, IResourceLocation> locationMap = new Dictionary<string, IResourceLocation>();
private Dictionary<string, IList<IResourceLocation>> dependencyMap = new Dictionary<string, IList<IResourceLocation>>();
private Dictionary<string, string> addressToKeyMap = new Dictionary<string, string>();
private List<string> cachedKeys = new List<string>();

void Start()
{
InitializeResourceLocator();
}

private void InitializeResourceLocator()
{
Debug.Log($"初始化ResourceLocator: {locatorId}");

// 这里通常会从ContentCatalogData加载位置信息
// 模拟加载一些位置数据
LoadMockCatalogData();
}

private void LoadMockCatalogData()
{
// 模拟从Catalog加载数据
var mockLocations = new[]
{
new MockResourceLocation("Assets/Prefabs/Player.prefab") { ProviderId = "PrefabProvider" },
new MockResourceLocation("Assets/Textures/UI/Background.png") { ProviderId = "TextureProvider" },
new MockResourceLocation("Assets/Audio/Music/Battle.mp3") { ProviderId = "AudioProvider" }
};

foreach (var location in mockLocations)
{
AddLocation(location);
}

Debug.Log($"加载了 {mockLocations.Length} 个模拟位置");
}

/// <summary>
/// 添加资源位置
/// </summary>
public void AddLocation(IResourceLocation location)
{
if (locationMap.ContainsKey(location.PrimaryKey))
{
Debug.LogWarning($"位置已存在: {location.PrimaryKey}");
return;
}

locationMap[location.PrimaryKey] = location;
addressToKeyMap[location.PrimaryKey] = location.PrimaryKey;

// 管理缓存大小
if (cachedKeys.Count >= maxCacheSize)
{
string oldestKey = cachedKeys[0];
cachedKeys.RemoveAt(0);
locationMap.Remove(oldestKey);
addressToKeyMap.Remove(oldestKey);
}

cachedKeys.Add(location.PrimaryKey);

Debug.Log($"添加位置: {location.PrimaryKey}");
}

/// <summary>
/// 获取资源位置
/// </summary>
public IResourceLocation Locate(string key)
{
if (locationMap.ContainsKey(key))
{
return locationMap[key];
}

// 尝试通过地址查找
if (addressToKeyMap.ContainsKey(key))
{
string actualKey = addressToKeyMap[key];
if (locationMap.ContainsKey(actualKey))
{
return locationMap[actualKey];
}
}

Debug.LogWarning($"未找到位置: {key}");
return null;
}

/// <summary>
/// 获取多个资源位置
/// </summary>
public bool Locate(string key, List<IResourceLocation> locations)
{
var location = Locate(key);
if (location != null)
{
locations.Add(location);
return true;
}
return false;
}

/// <summary>
/// 检查是否存在指定键的资源
/// </summary>
public bool Exists(string key, Type resourceType)
{
return locationMap.ContainsKey(key);
}

/// <summary>
/// 获取依赖关系
/// </summary>
public IList<IResourceLocation> GetDependencies(string key)
{
if (dependencyMap.ContainsKey(key))
{
return dependencyMap[key];
}

// 如果没有预存的依赖关系,返回空列表
return new List<IResourceLocation>();
}

/// <summary>
/// 设置依赖关系
/// </summary>
public void SetDependencies(string key, IList<IResourceLocation> dependencies)
{
dependencyMap[key] = dependencies;
}

/// <summary>
/// 获取所有位置键
/// </summary>
public string[] GetAllKeys()
{
var keys = new string[locationMap.Count];
locationMap.Keys.CopyTo(keys, 0);
return keys;
}

/// <summary>
/// 获取ResourceLocator统计
/// </summary>
public string GetLocatorStats()
{
var stats = new System.Text.StringBuilder();
stats.AppendLine("=== ResourceLocator统计 ===");
stats.AppendLine($"位置数量: {locationMap.Count}");
stats.AppendLine($"依赖关系数: {dependencyMap.Count}");
stats.AppendLine($"缓存键数: {cachedKeys.Count}");
stats.AppendLine($"最大缓存大小: {maxCacheSize}");
stats.AppendLine($"定位器ID: {locatorId}");

return stats.ToString();
}

/// <summary>
/// 清理ResourceLocator
/// </summary>
public void CleanupLocator()
{
locationMap.Clear();
dependencyMap.Clear();
addressToKeyMap.Clear();
cachedKeys.Clear();

Debug.Log("ResourceLocator清理完成");
}

void OnDestroy()
{
CleanupLocator();
}
}

ResourceManager与ResourceLocator的协作

ResourceManager和ResourceLocator之间存在紧密的协作关系:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.ResourceManagement;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceLocations;

public class ResourceManagerLocatorIntegration : MonoBehaviour
{
[Header("集成配置")]
public bool enableCaching = true;
public float cacheTimeout = 300f; // 5分钟

private ResourceManager resourceManager;
private ResourceLocatorArchitecture resourceLocator;
private Dictionary<string, CachedLocation> locationCache = new Dictionary<string, CachedLocation>();

[System.Serializable]
public class CachedLocation
{
public IResourceLocation location;
public DateTime cacheTime;
public float timeout;
}

void Start()
{
InitializeIntegration();
}

private void InitializeIntegration()
{
// 初始化ResourceManager
resourceManager = new ResourceManager();

// 初始化ResourceLocator
resourceLocator = GetComponent<ResourceLocatorArchitecture>();
if (resourceLocator == null)
{
resourceLocator = gameObject.AddComponent<ResourceLocatorArchitecture>();
}

Debug.Log("ResourceManager与ResourceLocator集成初始化完成");
}

/// <summary>
/// 完整的资源加载流程
/// </summary>
public AsyncOperationHandle<TObject> LoadAssetWithIntegration<TObject>(string address) where TObject : class
{
// 1. 首先检查缓存
if (enableCaching && locationCache.ContainsKey(address))
{
var cached = locationCache[address];
if ((DateTime.Now - cached.cacheTime).TotalSeconds < cached.timeout)
{
// 缓存有效,直接使用
return LoadFromCachedLocation<TObject>(cached.location);
}
else
{
// 缓存过期,移除
locationCache.Remove(address);
}
}

// 2. 使用ResourceLocator定位资源
var location = resourceLocator.Locate(address);
if (location == null)
{
Debug.LogError($"无法定位资源: {address}");
return default(AsyncOperationHandle<TObject>);
}

// 3. 缓存位置信息
if (enableCaching)
{
locationCache[address] = new CachedLocation
{
location = location,
cacheTime = DateTime.Now,
timeout = cacheTimeout
};
}

// 4. 使用ResourceManager执行加载
return LoadFromLocation<TObject>(location);
}

private AsyncOperationHandle<TObject> LoadFromCachedLocation<TObject>(IResourceLocation location) where TObject : class
{
// 从缓存位置加载
var provider = GetProviderForLocation(location);
if (provider == null)
{
Debug.LogError($"无法获取提供者: {location.PrimaryKey}");
return default(AsyncOperationHandle<TObject>);
}

var operation = resourceManager.CreateOperation<TObject>(provider, location, typeof(TObject));
resourceManager.StartOperation(operation, location);

Debug.Log($"从缓存位置加载: {location.PrimaryKey}");
return operation;
}

private AsyncOperationHandle<TObject> LoadFromLocation<TObject>(IResourceLocation location) where TObject : class
{
var provider = GetProviderForLocation(location);
if (provider == null)
{
Debug.LogError($"无法获取提供者: {location.PrimaryKey}");
return default(AsyncOperationHandle<TObject>);
}

var operation = resourceManager.CreateOperation<TObject>(provider, location, typeof(TObject));
resourceManager.StartOperation(operation, location);

Debug.Log($"从位置加载: {location.PrimaryKey}");
return operation;
}

private UnityEngine.ResourceManagement.ResourceProviders.IResourceProvider GetProviderForLocation(IResourceLocation location)
{
// 在实际系统中,这里会从ProviderManager获取
// 简化实现,返回模拟提供者
return new MockResourceProvider(location.ProviderId);
}

/// <summary>
/// 获取集成统计
/// </summary>
public string GetIntegrationStats()
{
var stats = new System.Text.StringBuilder();
stats.AppendLine("=== ResourceManager与ResourceLocator集成统计 ===");
stats.AppendLine(resourceManager != null ?
$"ResourceManager已初始化" : "ResourceManager未初始化");
stats.AppendLine(resourceLocator != null ?
$"ResourceLocator已初始化" : "ResourceLocator未初始化");
stats.AppendLine($"位置缓存数: {locationCache.Count}");
stats.AppendLine($"启用缓存: {enableCaching}");
stats.AppendLine($"缓存超时: {cacheTimeout}s");

if (resourceLocator != null)
{
stats.AppendLine();
stats.AppendLine(resourceLocator.GetLocatorStats());
}

return stats.ToString();
}

/// <summary>
/// 清理集成系统
/// </summary>
public void CleanupIntegration()
{
locationCache.Clear();

if (resourceManager != null)
{
resourceManager.Dispose();
}

Debug.Log("集成系统清理完成");
}

void OnDestroy()
{
CleanupIntegration();
}
}

地址解析流程

地址解析机制详解

Addressables的地址解析是整个系统的核心流程之一,它将开发者提供的地址字符串转换为实际的资源位置信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.ResourceManagement.ResourceLocations;

public class AddressResolutionSystem : MonoBehaviour
{
[Header("地址解析配置")]
public bool enableAddressCaching = true;
public bool enablePatternMatching = true;
public int maxAddressCacheSize = 500;

private Dictionary<string, ResolvedAddress> addressCache = new Dictionary<string, ResolvedAddress>();
private List<AddressPattern> addressPatterns = new List<AddressPattern>();
private ResourceLocatorArchitecture resourceLocator;

[System.Serializable]
public class ResolvedAddress
{
public string originalAddress;
public string resolvedKey;
public IResourceLocation location;
public DateTime resolveTime;
public List<IResourceLocation> dependencies;
}

[System.Serializable]
public class AddressPattern
{
public string pattern; // 如 "Prefabs/*"
public string replacement; // 如 "Assets/Prefabs/{0}.prefab"
public int priority; // 优先级,数值越小优先级越高
}

void Start()
{
resourceLocator = GetComponent<ResourceLocatorArchitecture>();
if (resourceLocator == null)
{
resourceLocator = gameObject.AddComponent<ResourceLocatorArchitecture>();
}

InitializeAddressPatterns();
}

private void InitializeAddressPatterns()
{
// 初始化默认地址模式
addressPatterns.Add(new AddressPattern
{
pattern = "Prefabs/*",
replacement = "Assets/Prefabs/{0}.prefab",
priority = 1
});
addressPatterns.Add(new AddressPattern
{
pattern = "Textures/*",
replacement = "Assets/Textures/{0}.png",
priority = 2
});
addressPatterns.Add(new AddressPattern
{
pattern = "Audio/*",
replacement = "Assets/Audio/{0}.mp3",
priority = 3
});

Debug.Log($"初始化了 {addressPatterns.Count} 个地址模式");
}

/// <summary>
/// 解析地址
/// </summary>
public ResolvedAddress ResolveAddress(string address)
{
// 1. 检查缓存
if (enableAddressCaching && addressCache.ContainsKey(address))
{
var cached = addressCache[address];
Debug.Log($"从缓存解析地址: {address} -> {cached.resolvedKey}");
return cached;
}

// 2. 应用模式匹配
string resolvedKey = address;
if (enablePatternMatching)
{
resolvedKey = ApplyAddressPatterns(address);
}

// 3. 在ResourceLocator中查找
var location = resourceLocator.Locate(resolvedKey);
if (location == null)
{
Debug.LogError($"无法解析地址: {address} -> {resolvedKey}");
return null;
}

// 4. 创建解析结果
var resolvedAddress = new ResolvedAddress
{
originalAddress = address,
resolvedKey = resolvedKey,
location = location,
resolveTime = DateTime.Now,
dependencies = new List<IResourceLocation>(resourceLocator.GetDependencies(resolvedKey))
};

// 5. 缓存结果
if (enableAddressCaching)
{
CacheAddress(address, resolvedAddress);
}

Debug.Log($"解析地址: {address} -> {resolvedKey}");
return resolvedAddress;
}

private string ApplyAddressPatterns(string address)
{
// 按优先级排序模式
var sortedPatterns = new List<AddressPattern>(addressPatterns);
sortedPatterns.Sort((a, b) => a.priority.CompareTo(b.priority));

foreach (var pattern in sortedPatterns)
{
if (MatchPattern(address, pattern.pattern))
{
// 应用模式替换
string patternWithoutWildcard = pattern.pattern.Replace("*", "");
if (address.StartsWith(patternWithoutWildcard))
{
string suffix = address.Substring(patternWithoutWildcard.Length);
return pattern.replacement.Replace("{0}", suffix);
}
}
}

// 如果没有匹配的模式,返回原始地址
return address;
}

private bool MatchPattern(string address, string pattern)
{
if (pattern.EndsWith("*"))
{
string prefix = pattern.Substring(0, pattern.Length - 1);
return address.StartsWith(prefix);
}

return address == pattern;
}

private void CacheAddress(string address, ResolvedAddress resolved)
{
// 检查缓存大小限制
if (addressCache.Count >= maxAddressCacheSize)
{
// 移除最旧的缓存项
var oldestKey = "";
DateTime oldestTime = DateTime.MaxValue;

foreach (var pair in addressCache)
{
if (pair.Value.resolveTime < oldestTime)
{
oldestTime = pair.Value.resolveTime;
oldestKey = pair.Key;
}
}

if (!string.IsNullOrEmpty(oldestKey))
{
addressCache.Remove(oldestKey);
}
}

addressCache[address] = resolved;
}

/// <summary>
/// 批量解析地址
/// </summary>
public List<ResolvedAddress> ResolveAddresses(string[] addresses)
{
var results = new List<ResolvedAddress>();

foreach (string address in addresses)
{
var resolved = ResolveAddress(address);
if (resolved != null)
{
results.Add(resolved);
}
}

return results;
}

/// <summary>
/// 预解析地址(用于性能优化)
/// </summary>
public void PreResolveAddresses(string[] addresses)
{
foreach (string address in addresses)
{
// 只解析,不返回结果,目的是填充缓存
ResolveAddress(address);
}

Debug.Log($"预解析了 {addresses.Length} 个地址");
}

/// <summary>
/// 获取地址解析统计
/// </summary>
public string GetResolutionStats()
{
var stats = new System.Text.StringBuilder();
stats.AppendLine("=== 地址解析统计 ===");
stats.AppendLine($"缓存地址数: {addressCache.Count}");
stats.AppendLine($"地址模式数: {addressPatterns.Count}");
stats.AppendLine($"启用缓存: {enableAddressCaching}");
stats.AppendLine($"启用模式匹配: {enablePatternMatching}");
stats.AppendLine($"最大缓存大小: {maxAddressCacheSize}");

if (addressCache.Count > 0)
{
stats.AppendLine();
stats.AppendLine("缓存详情:");
int count = 0;
foreach (var pair in addressCache)
{
if (count++ < 5) // 只显示前5个
{
stats.AppendLine($" {pair.Key} -> {pair.Value.resolvedKey}");
}
}
if (addressCache.Count > 5)
{
stats.AppendLine($" ... 还有 {addressCache.Count - 5} 个");
}
}

return stats.ToString();
}

/// <summary>
/// 清理地址缓存
/// </summary>
public void ClearAddressCache()
{
addressCache.Clear();
Debug.Log("地址缓存已清理");
}

void OnDestroy()
{
ClearAddressCache();
}
}

Provider系统详解

IResourceProvider接口

IResourceProvider是Addressables系统中负责实际资源加载的核心接口,所有资源加载操作最终都通过Provider来执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.ResourceManagement;
using UnityEngine.ResourceManagement.ResourceLocations;
using UnityEngine.ResourceManagement.ResourceProviders;

public class ProviderSystemArchitecture : MonoBehaviour
{
[Header("Provider系统配置")]
public bool enableProviderCaching = true;
public int maxProviderCacheSize = 100;

private Dictionary<string, IResourceProvider> providerCache = new Dictionary<string, IResourceProvider>();
private Dictionary<string, Type> providerTypeMap = new Dictionary<string, Type>();
private List<ActiveProviderOperation> activeOperations = new List<ActiveProviderOperation>();

[System.Serializable]
public class ActiveProviderOperation
{
public string providerId;
public string locationKey;
public DateTime startTime;
public bool isComplete;
}

void Start()
{
InitializeProviderTypes();
}

private void InitializeProviderTypes()
{
// 注册系统内置的Provider类型
providerTypeMap["PrefabProvider"] = typeof(PrefabProvider);
providerTypeMap["TextureProvider"] = typeof(TextureProvider);
providerTypeMap["AudioProvider"] = typeof(AudioProvider);
providerTypeMap["SceneProvider"] = typeof(SceneProvider);

Debug.Log($"注册了 {providerTypeMap.Count} 个Provider类型");
}

/// <summary>
/// 获取资源提供者
/// </summary>
public IResourceProvider GetProvider(string providerId)
{
// 检查缓存
if (enableProviderCaching && providerCache.ContainsKey(providerId))
{
return providerCache[providerId];
}

// 创建新的Provider实例
IResourceProvider provider = CreateProvider(providerId);
if (provider != null)
{
// 缓存Provider
if (enableProviderCaching)
{
CacheProvider(providerId, provider);
}
}

return provider;
}

private IResourceProvider CreateProvider(string providerId)
{
if (providerTypeMap.ContainsKey(providerId))
{
Type providerType = providerTypeMap[providerId];
return (IResourceProvider)Activator.CreateInstance(providerType);
}

// 如果没有找到预定义类型,返回通用Provider
return new GenericResourceProvider(providerId);
}

private void CacheProvider(string providerId, IResourceProvider provider)
{
// 检查缓存大小限制
if (providerCache.Count >= maxProviderCacheSize)
{
// 移除第一个缓存项(简单实现)
var firstKey = new List<string>(providerCache.Keys)[0];
providerCache.Remove(firstKey);
}

providerCache[providerId] = provider;
}

/// <summary>
/// 执行资源提供操作
/// </summary>
public void ProvideResource(IResourceLocation location, ProvideHandle provideHandle)
{
string providerId = location.Provider;
var provider = GetProvider(providerId);

if (provider != null)
{
// 记录活跃操作
var operation = new ActiveProviderOperation
{
providerId = providerId,
locationKey = location.PrimaryKey,
startTime = DateTime.Now,
isComplete = false
};
activeOperations.Add(operation);

// 执行提供操作
provider.Provide(provideHandle);

Debug.Log($"开始提供资源: {location.PrimaryKey} 通过 {providerId}");
}
else
{
Debug.LogError($"无法找到Provider: {providerId}");
provideHandle.Complete(null, false, new System.Exception($"Provider not found: {providerId}"));
}
}

/// <summary>
/// 释放资源
/// </summary>
public void ReleaseResource(IResourceLocation location, object asset)
{
string providerId = location.Provider;
var provider = GetProvider(providerId);

if (provider != null)
{
provider.Release(location, asset);
Debug.Log($"释放资源: {location.PrimaryKey}");
}
else
{
Debug.LogError($"无法释放资源,Provider不存在: {providerId}");
}
}

/// <summary>
/// 获取Provider统计
/// </summary>
public string GetProviderStats()
{
var stats = new System.Text.StringBuilder();
stats.AppendLine("=== Provider系统统计 ===");
stats.AppendLine($"注册Provider类型数: {providerTypeMap.Count}");
stats.AppendLine($"缓存Provider数: {providerCache.Count}");
stats.AppendLine($"活跃操作数: {activeOperations.Count}");
stats.AppendLine($"启用缓存: {enableProviderCaching}");
stats.AppendLine($"最大缓存大小: {maxProviderCacheSize}");

if (providerCache.Count > 0)
{
stats.AppendLine();
stats.AppendLine("缓存Provider:");
foreach (var pair in providerCache)
{
stats.AppendLine($" {pair.Key}: {pair.Value.GetType().Name}");
}
}

if (activeOperations.Count > 0)
{
stats.AppendLine();
stats.AppendLine("活跃操作:");
foreach (var op in activeOperations)
{
float duration = (float)(DateTime.Now - op.startTime).TotalSeconds;
stats.AppendLine($" {op.providerId} -> {op.locationKey} (运行 {duration:F2}s)");
}
}

return stats.ToString();
}

/// <summary>
/// 注册自定义Provider类型
/// </summary>
public void RegisterProviderType(string providerId, Type providerType)
{
if (!typeof(IResourceProvider).IsAssignableFrom(providerType))
{
Debug.LogError($"类型 {providerType.Name} 不实现 IResourceProvider 接口");
return;
}

providerTypeMap[providerId] = providerType;
Debug.Log($"注册Provider类型: {providerId} -> {providerType.Name}");
}

/// <summary>
/// 清理Provider系统
/// </summary>
public void CleanupProviders()
{
providerCache.Clear();
activeOperations.Clear();

Debug.Log("Provider系统清理完成");
}

void OnDestroy()
{
CleanupProviders();
}
}

/// <summary>
/// 预设Provider示例
/// </summary>
public class PrefabProvider : IResourceProvider
{
public string ProviderId => "PrefabProvider";

public void Provide(ProvideHandle provideHandle)
{
string locationName = provideHandle.Location.PrimaryKey;

// 模拟预设加载
System.Threading.Tasks.Task.Delay(50).ContinueWith(_ =>
{
// 在实际实现中,这里会加载实际的预设
var mockPrefab = new GameObject(locationName); // 模拟
provideHandle.Complete(mockPrefab, true, null);
});
}

public void Release(IResourceLocation location, object asset)
{
if (asset is GameObject go)
{
GameObject.Destroy(go);
}
}
}

/// <summary>
/// 纹理Provider示例
/// </summary>
public class TextureProvider : IResourceProvider
{
public string ProviderId => "TextureProvider";

public void Provide(ProvideHandle provideHandle)
{
string locationName = provideHandle.Location.PrimaryKey;

// 模拟纹理加载
System.Threading.Tasks.Task.Delay(80).ContinueWith(_ =>
{
// 在实际实现中,这里会加载实际的纹理
var mockTexture = new Texture2D(128, 128); // 模拟
provideHandle.Complete(mockTexture, true, null);
});
}

public void Release(IResourceLocation location, object asset)
{
if (asset is Texture2D texture)
{
UnityEngine.Object.Destroy(texture);
}
}
}

/// <summary>
/// 音频Provider示例
/// </summary>
public class AudioProvider : IResourceProvider
{
public string ProviderId => "AudioProvider";

public void Provide(ProvideHandle provideHandle)
{
string locationName = provideHandle.Location.PrimaryKey;

// 模拟音频加载
System.Threading.Tasks.Task.Delay(100).ContinueWith(_ =>
{
// 在实际实现中,这里会加载实际的音频
var mockAudio = new AudioClip(); // 模拟
provideHandle.Complete(mockAudio, true, null);
});
}

public void Release(IResourceLocation location, object asset)
{
if (asset is AudioClip audioClip)
{
UnityEngine.Object.Destroy(audioClip);
}
}
}

/// <summary>
/// 场景Provider示例
/// </summary>
public class SceneProvider : IResourceProvider
{
public string ProviderId => "SceneProvider";

public void Provide(ProvideHandle provideHandle)
{
string locationName = provideHandle.Location.PrimaryKey;

// 模拟场景加载
System.Threading.Tasks.Task.Delay(200).ContinueWith(_ =>
{
// 在实际实现中,这里会加载实际的场景
provideHandle.Complete(locationName, true, null); // 返回场景名称
});
}

public void Release(IResourceLocation location, object asset)
{
// 场景释放通常由SceneManager处理
Debug.Log($"场景释放请求: {location.PrimaryKey}");
}
}

/// <summary>
/// 通用资源Provider
/// </summary>
public class GenericResourceProvider : IResourceProvider
{
public string ProviderId { get; private set; }

public GenericResourceProvider(string providerId)
{
ProviderId = providerId;
}

public void Provide(ProvideHandle provideHandle)
{
string locationName = provideHandle.Location.PrimaryKey;

// 默认行为:返回位置名称作为结果
System.Threading.Tasks.Task.Delay(30).ContinueWith(_ =>
{
provideHandle.Complete(locationName, true, null);
});
}

public void Release(IResourceLocation location, object asset)
{
// 默认释放行为
if (asset is UnityEngine.Object unityObj)
{
UnityEngine.Object.Destroy(unityObj);
}
}
}

Handle机制深入

AsyncOperationHandle详解

AsyncOperationHandle是Addressables系统中管理异步操作的核心机制,它提供了统一的异步操作接口和生命周期管理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.ResourceManagement;
using UnityEngine.ResourceManagement.AsyncOperations;

public class HandleMechanismDeepDive : MonoBehaviour
{
[Header("Handle机制配置")]
public bool enableHandleTracking = true;
public float handleTimeout = 60f;
public bool enableReferenceCounting = true;

private Dictionary<string, TrackedHandle> trackedHandles = new Dictionary<string, TrackedHandle>();
private int handleCounter = 0;

[System.Serializable]
public class TrackedHandle
{
public string handleId;
public AsyncOperationHandle handle;
public DateTime createTime;
public int referenceCount;
public string resourceAddress;
public AsyncOperationStatus status;
public System.Exception error;
}

void Start()
{
Debug.Log("Handle机制深度解析系统启动");
}

/// <summary>
/// 创建跟踪的异步操作句柄
/// </summary>
public AsyncOperationHandle CreateTrackedHandle(string resourceAddress)
{
string handleId = $"Handle_{++handleCounter:D4}";

// 在实际系统中,这里会创建真实的AsyncOperationHandle
// 简化实现,使用模拟句柄
var trackedHandle = new TrackedHandle
{
handleId = handleId,
resourceAddress = resourceAddress,
createTime = DateTime.Now,
referenceCount = enableReferenceCounting ? 1 : 0,
status = AsyncOperationStatus.None
};

if (enableHandleTracking)
{
trackedHandles[handleId] = trackedHandle;
}

Debug.Log($"创建句柄: {handleId} -> {resourceAddress}");
return CreateMockHandle(handleId, resourceAddress);
}

private AsyncOperationHandle CreateMockHandle(string handleId, string resourceAddress)
{
// 创建模拟的AsyncOperationHandle
// 在实际实现中,这会是ResourceManager.CreateOperation的结果
var handle = new AsyncOperationHandle();

// 模拟异步加载过程
System.Threading.Tasks.Task.Delay(100).ContinueWith(_ =>
{
UpdateHandleStatus(handleId, AsyncOperationStatus.Succeeded);
});

return handle;
}

/// <summary>
/// 更新句柄状态
/// </summary>
private void UpdateHandleStatus(string handleId, AsyncOperationStatus status)
{
if (trackedHandles.ContainsKey(handleId))
{
var tracked = trackedHandles[handleId];
tracked.status = status;

if (status == AsyncOperationStatus.Failed)
{
tracked.error = new System.Exception($"操作失败: {tracked.resourceAddress}");
}

Debug.Log($"句柄状态更新: {handleId} -> {status}");
}
}

/// <summary>
/// 增加句柄引用计数
/// </summary>
public bool RetainHandle(string handleId)
{
if (trackedHandles.ContainsKey(handleId))
{
var tracked = trackedHandles[handleId];
tracked.referenceCount++;

Debug.Log($"句柄引用增加: {handleId}, 当前引用: {tracked.referenceCount}");
return true;
}

Debug.LogWarning($"句柄不存在: {handleId}");
return false;
}

/// <summary>
/// 减少句柄引用计数(释放句柄)
/// </summary>
public bool ReleaseHandle(string handleId)
{
if (trackedHandles.ContainsKey(handleId))
{
var tracked = trackedHandles[handleId];
tracked.referenceCount--;

Debug.Log($"句柄引用减少: {handleId}, 当前引用: {tracked.referenceCount}");

// 如果引用计数为0且启用了引用计数管理,清理句柄
if (enableReferenceCounting && tracked.referenceCount <= 0)
{
CleanupHandle(handleId);
return true;
}

return true;
}

Debug.LogWarning($"句柄不存在: {handleId}");
return false;
}

/// <summary>
/// 清理句柄
/// </summary>
private void CleanupHandle(string handleId)
{
if (trackedHandles.ContainsKey(handleId))
{
var tracked = trackedHandles[handleId];

Debug.Log($"清理句柄: {handleId}, 资源: {tracked.resourceAddress}");

// 在实际系统中,这里会释放相关资源
// 模拟资源释放

trackedHandles.Remove(handleId);
}
}

/// <summary>
/// 获取句柄信息
/// </summary>
public string GetHandleInfo(string handleId)
{
if (trackedHandles.ContainsKey(handleId))
{
var tracked = trackedHandles[handleId];
var info = new System.Text.StringBuilder();

info.AppendLine($"=== 句柄信息: {handleId} ===");
info.AppendLine($"资源地址: {tracked.resourceAddress}");
info.AppendLine($"创建时间: {tracked.createTime:HH:mm:ss.fff}");
info.AppendLine($"引用计数: {tracked.referenceCount}");
info.AppendLine($"状态: {tracked.status}");
info.AppendLine($"运行时间: {(DateTime.Now - tracked.createTime).TotalSeconds:F2}s");

if (tracked.error != null)
{
info.AppendLine($"错误: {tracked.error.Message}");
}

return info.ToString();
}

return $"句柄不存在: {handleId}";
}

/// <summary>
/// 获取所有句柄统计
/// </summary>
public string GetAllHandleStats()
{
var stats = new System.Text.StringBuilder();
stats.AppendLine("=== 所有句柄统计 ===");
stats.AppendLine($"跟踪句柄数: {trackedHandles.Count}");
stats.AppendLine($"总句柄计数: {handleCounter}");
stats.AppendLine($"启用引用计数: {enableReferenceCounting}");
stats.AppendLine($"启用跟踪: {enableHandleTracking}");
stats.AppendLine($"超时时间: {handleTimeout}s");

if (trackedHandles.Count > 0)
{
stats.AppendLine();
stats.AppendLine("句柄详情:");

int count = 0;
foreach (var pair in trackedHandles)
{
if (count++ < 10) // 只显示前10个
{
var tracked = pair.Value;
float age = (float)(DateTime.Now - tracked.createTime).TotalSeconds;
stats.AppendLine($" {pair.Key}: {tracked.resourceAddress} " +
$"(引用:{tracked.referenceCount}, 状态:{tracked.status}, 年龄:{age:F1}s)");
}
}

if (trackedHandles.Count > 10)
{
stats.AppendLine($" ... 还有 {trackedHandles.Count - 10} 个");
}
}

return stats.ToString();
}

/// <summary>
/// 检查超时句柄
/// </summary>
public void CheckTimeoutHandles()
{
var timeoutHandles = new List<string>();

foreach (var pair in trackedHandles)
{
var tracked = pair.Value;
float age = (float)(DateTime.Now - tracked.createTime).TotalSeconds;

if (age > handleTimeout)
{
timeoutHandles.Add(pair.Key);
}
}

foreach (string handleId in timeoutHandles)
{
Debug.LogWarning($"句柄超时: {handleId}");
CleanupHandle(handleId);
}

if (timeoutHandles.Count > 0)
{
Debug.Log($"清理了 {timeoutHandles.Count} 个超时句柄");
}
}

/// <summary>
/// 批量操作句柄
/// </summary>
public void BatchOperationHandles(List<string> handleIds, string operation)
{
foreach (string handleId in handleIds)
{
switch (operation.ToLower())
{
case "retain":
RetainHandle(handleId);
break;
case "release":
ReleaseHandle(handleId);
break;
case "info":
Debug.Log(GetHandleInfo(handleId));
break;
}
}
}

/// <summary>
/// 清理所有句柄
/// </summary>
public void CleanupAllHandles()
{
var handlesToCleanup = new List<string>(trackedHandles.Keys);

foreach (string handleId in handlesToCleanup)
{
CleanupHandle(handleId);
}

handleCounter = 0;

Debug.Log($"清理了所有 {handlesToCleanup.Count} 个句柄");
}

void Update()
{
// 定期检查超时句柄
if (Time.frameCount % 300 == 0) // 每300帧检查一次
{
CheckTimeoutHandles();
}
}

void OnDestroy()
{
CleanupAllHandles();
}
}

AsyncOperationHandle生命周期

AsyncOperationHandle的生命周期管理是Addressables系统中确保资源正确加载和释放的关键机制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.ResourceManagement;
using UnityEngine.ResourceManagement.AsyncOperations;

public class HandleLifecycleManager : MonoBehaviour
{
[Header("生命周期配置")]
public float operationTimeout = 120f;
public bool enableAutoRelease = true;
public float autoReleaseDelay = 5f;

private Dictionary<string, HandleLifecycleInfo> lifecycleInfos = new Dictionary<string, HandleLifecycleInfo>();

[System.Serializable]
public class HandleLifecycleInfo
{
public string handleId;
public AsyncOperationHandle handle;
public DateTime startTime;
public DateTime completeTime;
public AsyncOperationStatus status;
public int referenceCount;
public bool autoReleaseScheduled;
public System.Action onCompleted;
public System.Action<System.Exception> onError;
public System.Action<float> onProgress;
}

void Start()
{
Debug.Log("Handle生命周期管理系统启动");
}

/// <summary>
/// 开始跟踪句柄生命周期
/// </summary>
public string TrackHandleLifecycle(AsyncOperationHandle handle,
System.Action onCompleted = null,
System.Action<System.Exception> onError = null,
System.Action<float> onProgress = null)
{
string handleId = $"Lifecycle_{DateTime.Now:HHmmss}_{UnityEngine.Random.Range(1000, 9999)}";

var lifecycleInfo = new HandleLifecycleInfo
{
handleId = handleId,
handle = handle,
startTime = DateTime.Now,
status = AsyncOperationStatus.None,
referenceCount = 1,
onCompleted = onCompleted,
onError = onError,
onProgress = onProgress
};

lifecycleInfos[handleId] = lifecycleInfo;

// 监听句柄事件
SetupHandleListeners(lifecycleInfo);

Debug.Log($"开始跟踪句柄生命周期: {handleId}");
return handleId;
}

private void SetupHandleListeners(HandleLifecycleInfo lifecycleInfo)
{
// 监听完成事件
lifecycleInfo.handle.Completed += (op) =>
{
lifecycleInfo.completeTime = DateTime.Now;
lifecycleInfo.status = op.Status;

if (op.Status == AsyncOperationStatus.Succeeded)
{
lifecycleInfo.onCompleted?.Invoke();
Debug.Log($"句柄完成成功: {lifecycleInfo.handleId}");
}
else
{
lifecycleInfo.onError?.Invoke(op.OperationException);
Debug.LogError($"句柄完成失败: {lifecycleInfo.handleId}, 错误: {op.OperationException?.Message}");
}

// 如果启用了自动释放,安排释放
if (enableAutoRelease)
{
ScheduleAutoRelease(lifecycleInfo);
}
};

// 监听进度事件
if (lifecycleInfo.onProgress != null)
{
lifecycleInfo.handle.PercentCompleteChanged += (op) =>
{
lifecycleInfo.onProgress?.Invoke(op.PercentComplete);
};
}
}

private void ScheduleAutoRelease(HandleLifecycleInfo lifecycleInfo)
{
lifecycleInfo.autoReleaseScheduled = true;

// 使用协程延迟释放
StartCoroutine(AutoReleaseCoroutine(lifecycleInfo));
}

private System.Collections.IEnumerator AutoReleaseCoroutine(HandleLifecycleInfo lifecycleInfo)
{
yield return new WaitForSeconds(autoReleaseDelay);

if (lifecycleInfos.ContainsKey(lifecycleInfo.handleId))
{
ForceReleaseHandle(lifecycleInfo.handleId);
}
}

/// <summary>
/// 强制释放句柄
/// </summary>
public bool ForceReleaseHandle(string handleId)
{
if (lifecycleInfos.ContainsKey(handleId))
{
var lifecycleInfo = lifecycleInfos[handleId];

// 在实际系统中,这里会调用ResourceManager.Release
// 模拟释放过程
Debug.Log($"强制释放句柄: {handleId}");

lifecycleInfos.Remove(handleId);
return true;
}

Debug.LogWarning($"句柄不存在: {handleId}");
return false;
}

/// <summary>
/// 增加句柄引用
/// </summary>
public bool RetainHandleReference(string handleId)
{
if (lifecycleInfos.ContainsKey(handleId))
{
var lifecycleInfo = lifecycleInfos[handleId];
lifecycleInfo.referenceCount++;

Debug.Log($"句柄引用增加: {handleId}, 当前: {lifecycleInfo.referenceCount}");
return true;
}

Debug.LogWarning($"句柄不存在: {handleId}");
return false;
}

/// <summary>
/// 减少句柄引用
/// </summary>
public bool ReleaseHandleReference(string handleId)
{
if (lifecycleInfos.ContainsKey(handleId))
{
var lifecycleInfo = lifecycleInfos[handleId];
lifecycleInfo.referenceCount--;

Debug.Log($"句柄引用减少: {handleId}, 当前: {lifecycleInfo.referenceCount}");

// 如果引用计数为0,释放句柄
if (lifecycleInfo.referenceCount <= 0)
{
return ForceReleaseHandle(handleId);
}

return true;
}

Debug.LogWarning($"句柄不存在: {handleId}");
return false;
}

/// <summary>
/// 获取生命周期统计
/// </summary>
public string GetLifecycleStats()
{
var stats = new System.Text.StringBuilder();
stats.AppendLine("=== Handle生命周期统计 ===");
stats.AppendLine($"跟踪句柄数: {lifecycleInfos.Count}");
stats.AppendLine($"操作超时: {operationTimeout}s");
stats.AppendLine($"启用自动释放: {enableAutoRelease}");
stats.AppendLine($"自动释放延迟: {autoReleaseDelay}s");

if (lifecycleInfos.Count > 0)
{
stats.AppendLine();
stats.AppendLine("活跃句柄:");

foreach (var pair in lifecycleInfos)
{
var info = pair.Value;
float duration = (float)(DateTime.Now - info.startTime).TotalSeconds;

string statusStr = info.status == AsyncOperationStatus.None ? "Running" : info.status.ToString();
string ageStr = info.completeTime != default(DateTime) ?
$"{(float)(info.completeTime - info.startTime).TotalSeconds:F2}s" : $"{duration:F2}s";

stats.AppendLine($" {pair.Key}: 引用{info.referenceCount}, 状态{statusStr}, 时长{ageStr}");
}
}

return stats.ToString();
}

/// <summary>
/// 检查超时句柄
/// </summary>
public void CheckTimeoutHandles()
{
var timeoutHandles = new List<string>();

foreach (var pair in lifecycleInfos)
{
var info = pair.Value;
float duration = (float)(DateTime.Now - info.startTime).TotalSeconds;

if (duration > operationTimeout)
{
timeoutHandles.Add(pair.Key);
}
}

foreach (string handleId in timeoutHandles)
{
Debug.LogWarning($"句柄超时: {handleId}");
ForceReleaseHandle(handleId);
}

if (timeoutHandles.Count > 0)
{
Debug.Log($"清理了 {timeoutHandles.Count} 个超时句柄");
}
}

/// <summary>
/// 获取句柄详细信息
/// </summary>
public string GetHandleDetails(string handleId)
{
if (lifecycleInfos.ContainsKey(handleId))
{
var info = lifecycleInfos[handleId];
var details = new System.Text.StringBuilder();

details.AppendLine($"=== 句柄详细信息: {handleId} ===");
details.AppendLine($"引用计数: {info.referenceCount}");
details.AppendLine($"状态: {info.status}");
details.AppendLine($"开始时间: {info.startTime:HH:mm:ss.fff}");
details.AppendLine($"完成时间: {(info.completeTime != default(DateTime) ? info.completeTime.ToString("HH:mm:ss.fff") : "未完成")}");
details.AppendLine($"运行时长: {(float)(DateTime.Now - info.startTime).TotalSeconds:F2}s");
details.AppendLine($"自动释放已安排: {info.autoReleaseScheduled}");

return details.ToString();
}

return $"句柄不存在: {handleId}";
}

void Update()
{
// 定期检查超时
if (Time.frameCount % 600 == 0) // 每600帧检查一次
{
CheckTimeoutHandles();
}
}

void OnDestroy()
{
// 清理所有跟踪的句柄
var handlesToCleanup = new List<string>(lifecycleInfos.Keys);

foreach (string handleId in handlesToCleanup)
{
ForceReleaseHandle(handleId);
}

Debug.Log($"生命周期管理系统清理完成,共清理 {handlesToCleanup.Count} 个句柄");
}
}

通过本章的深入学习,您已经全面理解了Addressables系统的架构设计、核心组件关系、地址解析流程、Provider系统以及Handle机制的生命周期管理。这些知识将帮助您更好地理解和运用Addressables系统,为后续的底层原理学习打下坚实基础。