mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
feat(ui): 实现UI实例池化管理和生命周期优化
- 添加UI实例管理策略枚举(AlwaysCreate、Reuse、Pooled) - 在GodotUiFactory中实现缓存池和实例回收机制 - 扩展IUiFactory接口支持预加载、回收和缓存管理功能 - 更新UiRouterBase支持实例策略参数传递 - 重构Pop策略将Hide重命名为Cache以明确语义 - 移除项目文件中的冗余文件夹引用 - 添加日志记录便于调试和监控实例状态 - 实现批量预加载和全量缓存清理功能 - 优化页面替换逻辑支持实例复用和池化管理
This commit is contained in:
parent
c2b046e185
commit
760cc71985
@ -6,27 +6,13 @@
|
||||
/// </summary>
|
||||
public enum UiTransitionPolicy
|
||||
{
|
||||
/// <summary>
|
||||
/// 出栈即销毁(一次性页面)
|
||||
/// 页面从栈中移除时会完全销毁实例
|
||||
/// </summary>
|
||||
Destroy,
|
||||
|
||||
/// <summary>
|
||||
/// 出栈隐藏,保留实例
|
||||
/// 页面从栈中移除时仅隐藏显示,保留实例以便后续重用
|
||||
/// </summary>
|
||||
Hide,
|
||||
|
||||
/// <summary>
|
||||
/// 覆盖显示(不影响下层页面)
|
||||
/// 当前页面覆盖在其他页面之上显示,不影响下层页面的状态
|
||||
/// </summary>
|
||||
Overlay,
|
||||
|
||||
/// <summary>
|
||||
/// 独占显示(下层页面 Pause + Hide)
|
||||
/// 当前页面独占显示区域,下层页面会被暂停并隐藏
|
||||
/// </summary>
|
||||
Exclusive
|
||||
Exclusive,
|
||||
|
||||
/// <summary>
|
||||
/// 覆盖显示(下层页面仅 Pause,不隐藏)
|
||||
/// </summary>
|
||||
Overlay
|
||||
}
|
||||
@ -8,9 +8,48 @@ namespace GFramework.Game.Abstractions.ui;
|
||||
public interface IUiFactory : IContextUtility
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据UI键值创建对应的UI页面实例
|
||||
/// 创建或获取UI页面实例
|
||||
/// </summary>
|
||||
/// <param name="uiKey">UI标识键</param>
|
||||
/// <param name="policy">实例管理策略</param>
|
||||
/// <returns>UI页面实例</returns>
|
||||
IUiPageBehavior GetOrCreate(string uiKey, UiInstancePolicy policy = UiInstancePolicy.AlwaysCreate);
|
||||
|
||||
/// <summary>
|
||||
/// 仅创建新实例(不使用缓存)
|
||||
/// </summary>
|
||||
/// <param name="uiKey">UI标识键,用于确定要创建的具体UI页面类型</param>
|
||||
/// <returns>创建的UI页面实例,实现IUiPage接口</returns>
|
||||
IUiPageBehavior Create(string uiKey);
|
||||
|
||||
/// <summary>
|
||||
/// 预加载UI资源到缓存池
|
||||
/// </summary>
|
||||
/// <param name="uiKey">UI标识键</param>
|
||||
/// <param name="count">预加载数量,默认1个</param>
|
||||
void Preload(string uiKey, int count = 1);
|
||||
|
||||
/// <summary>
|
||||
/// 批量预加载
|
||||
/// </summary>
|
||||
void PreloadBatch(params string[] uiKeys);
|
||||
|
||||
/// <summary>
|
||||
/// 回收实例到缓存池
|
||||
/// </summary>
|
||||
/// <param name="page">要回收的页面实例</param>
|
||||
void Recycle(IUiPageBehavior page);
|
||||
|
||||
/// <summary>
|
||||
/// 清理指定UI的缓存实例
|
||||
/// </summary>
|
||||
void ClearCache(string uiKey);
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有缓存
|
||||
/// </summary>
|
||||
void ClearAllCache();
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否有缓存的实例
|
||||
/// </summary>
|
||||
bool HasCached(string uiKey);
|
||||
}
|
||||
@ -25,7 +25,10 @@ public interface IUiRouter : ISystem
|
||||
/// <param name="uiKey">UI界面的唯一标识符</param>
|
||||
/// <param name="param">进入界面的参数,可为空</param>
|
||||
/// <param name="policy">界面切换策略,默认为Exclusive(独占)</param>
|
||||
void Push(string uiKey, IUiPageEnterParam? param = null, UiTransitionPolicy policy = UiTransitionPolicy.Exclusive);
|
||||
/// <param name="instancePolicy">实例管理策略,默认为Reuse(复用)</param>
|
||||
void Push(string uiKey, IUiPageEnterParam? param = null, UiTransitionPolicy policy = UiTransitionPolicy.Exclusive,
|
||||
UiInstancePolicy instancePolicy = UiInstancePolicy.Reuse);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将已存在的UI页面压入路由栈
|
||||
@ -37,6 +40,7 @@ public interface IUiRouter : ISystem
|
||||
void Push(IUiPageBehavior page, IUiPageEnterParam? param = null,
|
||||
UiTransitionPolicy policy = UiTransitionPolicy.Exclusive);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 弹出路由栈顶的UI界面,返回到上一个界面
|
||||
/// </summary>
|
||||
@ -44,21 +48,33 @@ public interface IUiRouter : ISystem
|
||||
void Pop(UiPopPolicy policy = UiPopPolicy.Destroy);
|
||||
|
||||
/// <summary>
|
||||
/// 替换当前UI界面为指定的新界面
|
||||
/// 替换当前所有页面为新页面(基于uiKey)
|
||||
/// </summary>
|
||||
/// <param name="uiKey">新UI界面的唯一标识符</param>
|
||||
/// <param name="param">进入界面的参数,可为空</param>
|
||||
/// <param name="popPolicy">界面弹出策略,默认为销毁当前界面</param>
|
||||
/// <param name="pushPolicy">界面过渡策略,默认为独占模式</param>
|
||||
void Replace(
|
||||
/// <param name="uiKey">新UI页面标识符</param>
|
||||
/// <param name="param">页面进入参数,可为空</param>
|
||||
/// <param name="popPolicy">弹出页面时的销毁策略,默认为销毁</param>
|
||||
/// <param name="pushPolicy">推入页面时的过渡策略,默认为独占</param>
|
||||
/// <param name="instancePolicy">实例管理策略</param>
|
||||
public void Replace(
|
||||
string uiKey,
|
||||
IUiPageEnterParam? param = null,
|
||||
UiPopPolicy popPolicy = UiPopPolicy.Destroy,
|
||||
UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive
|
||||
);
|
||||
|
||||
UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive,
|
||||
UiInstancePolicy instancePolicy = UiInstancePolicy.Reuse);
|
||||
|
||||
/// <summary>
|
||||
/// 替换当前所有页面为已存在的页面(基于实例)
|
||||
/// </summary>
|
||||
/// <param name="page">已创建的UI页面行为实例</param>
|
||||
/// <param name="param">页面进入参数,可为空</param>
|
||||
/// <param name="popPolicy">弹出页面时的销毁策略,默认为销毁</param>
|
||||
/// <param name="pushPolicy">推入页面时的过渡策略,默认为独占</param>
|
||||
public void Replace(
|
||||
IUiPageBehavior page,
|
||||
IUiPageEnterParam? param = null,
|
||||
UiPopPolicy popPolicy = UiPopPolicy.Destroy,
|
||||
UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive);
|
||||
/// <summary>
|
||||
/// 清空所有UI界面,重置路由状态
|
||||
/// </summary>
|
||||
void Clear();
|
||||
|
||||
23
GFramework.Game.Abstractions/ui/UiInstancePolicy.cs
Normal file
23
GFramework.Game.Abstractions/ui/UiInstancePolicy.cs
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
namespace GFramework.Game.Abstractions.ui;
|
||||
|
||||
/// <summary>
|
||||
/// UI页面实例管理策略(控制实例的生命周期)
|
||||
/// </summary>
|
||||
public enum UiInstancePolicy
|
||||
{
|
||||
/// <summary>
|
||||
/// 总是创建新实例
|
||||
/// </summary>
|
||||
AlwaysCreate,
|
||||
|
||||
/// <summary>
|
||||
/// 复用已存在的实例(如果有)
|
||||
/// </summary>
|
||||
Reuse,
|
||||
|
||||
/// <summary>
|
||||
/// 从预加载池中获取或创建
|
||||
/// </summary>
|
||||
Pooled
|
||||
}
|
||||
@ -6,12 +6,12 @@
|
||||
public enum UiPopPolicy
|
||||
{
|
||||
/// <summary>
|
||||
/// 销毁模式:关闭时完全销毁UI对象
|
||||
/// 销毁实例
|
||||
/// </summary>
|
||||
Destroy,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 隐藏模式:关闭时仅隐藏UI对象,保留实例
|
||||
/// 隐藏但保留实例(下次Push可复用)
|
||||
/// </summary>
|
||||
Hide
|
||||
Cache
|
||||
}
|
||||
@ -13,7 +13,4 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="registry\"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@ -1,7 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using GFramework.Core.Abstractions.logging;
|
||||
using GFramework.Core.extensions;
|
||||
using GFramework.Core.logging;
|
||||
@ -62,18 +58,17 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
|
||||
_uiRoot = root;
|
||||
Log.Debug("Bind UI Root: {0}", root.GetType().Name);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将指定UI页面压入栈顶并显示
|
||||
/// 将指定的UI界面压入路由栈,显示新的UI界面
|
||||
/// </summary>
|
||||
/// <param name="uiKey">UI页面标识符</param>
|
||||
/// <param name="param">页面进入参数,可为空</param>
|
||||
/// <param name="policy">页面切换策略</param>
|
||||
public void Push(
|
||||
string uiKey,
|
||||
IUiPageEnterParam? param = null,
|
||||
UiTransitionPolicy policy = UiTransitionPolicy.Exclusive
|
||||
)
|
||||
/// <param name="uiKey">UI界面的唯一标识符</param>
|
||||
/// <param name="param">进入界面的参数,可为空</param>
|
||||
/// <param name="policy">界面切换策略,默认为Exclusive(独占)</param>
|
||||
/// <param name="instancePolicy">实例管理策略,默认为Reuse(复用)</param>
|
||||
public void Push(string uiKey, IUiPageEnterParam? param = null, UiTransitionPolicy policy = UiTransitionPolicy.Exclusive,
|
||||
UiInstancePolicy instancePolicy = UiInstancePolicy.Reuse)
|
||||
{
|
||||
if (IsTop(uiKey))
|
||||
{
|
||||
@ -84,15 +79,15 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
|
||||
var @event = CreateEvent(uiKey, UiTransitionType.Push, policy, param);
|
||||
|
||||
Log.Debug(
|
||||
"Push UI Page: key={0}, policy={1}, stackBefore={2}",
|
||||
uiKey, policy, _stack.Count
|
||||
"Push UI Page: key={0}, policy={1}, instancePolicy={2}, stackBefore={3}",
|
||||
uiKey, policy, instancePolicy, _stack.Count
|
||||
);
|
||||
|
||||
BeforeChange(@event);
|
||||
|
||||
// 先创建页面,然后使用统一的Push逻辑
|
||||
var page = _factory.Create(uiKey);
|
||||
Log.Debug("Create UI Page instance: {0}", page.GetType().Name);
|
||||
// 使用工厂的增强方法获取实例
|
||||
var page = _factory.GetOrCreate(uiKey, instancePolicy);
|
||||
Log.Debug("Get/Create UI Page instance: {0}", page.GetType().Name);
|
||||
|
||||
DoPushPageInternal(page, param, policy);
|
||||
|
||||
@ -144,8 +139,8 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
|
||||
}
|
||||
|
||||
var nextUiKey = _stack.Count > 1
|
||||
? _stack.ElementAt(1).View.GetType().Name
|
||||
: string.Empty;
|
||||
? _stack.ElementAt(1).Key // 使用 Key 而不是 View.GetType().Name
|
||||
: throw new InvalidOperationException("Stack is empty");
|
||||
var @event = CreateEvent(nextUiKey, UiTransitionType.Pop);
|
||||
|
||||
BeforeChange(@event);
|
||||
@ -156,33 +151,67 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 替换当前所有页面为新页面
|
||||
/// 替换当前所有页面为新页面(基于uiKey)
|
||||
/// </summary>
|
||||
/// <param name="uiKey">新UI页面标识符</param>
|
||||
/// <param name="param">页面进入参数,可为空</param>
|
||||
/// <param name="popPolicy">弹出页面时的销毁策略,默认为销毁</param>
|
||||
/// <param name="pushPolicy">推入页面时的过渡策略,默认为独占</param>
|
||||
/// <param name="instancePolicy">实例管理策略</param>
|
||||
public void Replace(
|
||||
string uiKey,
|
||||
IUiPageEnterParam? param = null,
|
||||
UiPopPolicy popPolicy = UiPopPolicy.Destroy,
|
||||
UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive
|
||||
)
|
||||
UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive,
|
||||
UiInstancePolicy instancePolicy = UiInstancePolicy.Reuse)
|
||||
{
|
||||
var @event = CreateEvent(uiKey, UiTransitionType.Replace, pushPolicy, param);
|
||||
|
||||
Log.Debug(
|
||||
"Replace UI Stack with page: key={0}, popPolicy={1}, pushPolicy={2}",
|
||||
"Replace UI Stack with page: key={0}, popPolicy={1}, pushPolicy={2}, instancePolicy={3}",
|
||||
uiKey, popPolicy, pushPolicy, instancePolicy
|
||||
);
|
||||
|
||||
BeforeChange(@event);
|
||||
|
||||
// 使用内部方法清空栈,避免触发额外的Pipeline
|
||||
DoClearInternal(popPolicy);
|
||||
|
||||
// 使用工厂的增强方法获取实例
|
||||
var page = _factory.GetOrCreate(uiKey, instancePolicy);
|
||||
Log.Debug("Get/Create UI Page instance for Replace: {0}", page.GetType().Name);
|
||||
|
||||
DoPushPageInternal(page, param, pushPolicy);
|
||||
|
||||
AfterChange(@event);
|
||||
}
|
||||
/// <summary>
|
||||
/// 替换当前所有页面为已存在的页面(基于实例)
|
||||
/// </summary>
|
||||
/// <param name="page">已创建的UI页面行为实例</param>
|
||||
/// <param name="param">页面进入参数,可为空</param>
|
||||
/// <param name="popPolicy">弹出页面时的销毁策略,默认为销毁</param>
|
||||
/// <param name="pushPolicy">推入页面时的过渡策略,默认为独占</param>
|
||||
public void Replace(
|
||||
IUiPageBehavior page,
|
||||
IUiPageEnterParam? param = null,
|
||||
UiPopPolicy popPolicy = UiPopPolicy.Destroy,
|
||||
UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive)
|
||||
{
|
||||
var uiKey = page.Key;
|
||||
var @event = CreateEvent(uiKey, UiTransitionType.Replace, pushPolicy, param);
|
||||
|
||||
Log.Debug(
|
||||
"Replace UI Stack with existing page: key={0}, popPolicy={1}, pushPolicy={2}",
|
||||
uiKey, popPolicy, pushPolicy
|
||||
);
|
||||
|
||||
BeforeChange(@event);
|
||||
|
||||
// 使用内部方法,避免触发额外的Pipeline
|
||||
// 清空栈
|
||||
DoClearInternal(popPolicy);
|
||||
|
||||
var page = _factory.Create(uiKey);
|
||||
Log.Debug("Create UI Page instance for Replace: {0}", page.GetType().Name);
|
||||
Log.Debug("Use existing UI Page instance for Replace: {0}", page.GetType().Name);
|
||||
DoPushPageInternal(page, param, pushPolicy);
|
||||
|
||||
AfterChange(@event);
|
||||
@ -372,11 +401,13 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
|
||||
{
|
||||
Log.Debug("Destroy UI Page: {0}", top.GetType().Name);
|
||||
_uiRoot.RemoveUiPage(top);
|
||||
// 不回收,直接销毁
|
||||
}
|
||||
else
|
||||
else // UiPopPolicy.Cache
|
||||
{
|
||||
Log.Debug("Hide UI Page: {0}", top.GetType().Name);
|
||||
top.OnHide();
|
||||
Log.Debug("Cache UI Page: {0}", top.GetType().Name);
|
||||
_uiRoot.RemoveUiPage(top);
|
||||
_factory.Recycle(top); // 回收到池中
|
||||
}
|
||||
|
||||
if (_stack.Count > 0)
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
using GFramework.Core.extensions;
|
||||
using GFramework.Core.Abstractions.logging;
|
||||
using GFramework.Core.extensions;
|
||||
using GFramework.Core.logging;
|
||||
using GFramework.Core.utility;
|
||||
using GFramework.Game.Abstractions.ui;
|
||||
using GFramework.Godot.extensions;
|
||||
using Godot;
|
||||
|
||||
namespace GFramework.Godot.ui;
|
||||
|
||||
@ -10,39 +14,204 @@ namespace GFramework.Godot.ui;
|
||||
/// </summary>
|
||||
public class GodotUiFactory : AbstractContextUtility, IUiFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// UI注册表,用于存储和获取PackedScene类型的UI资源
|
||||
/// </summary>
|
||||
private static readonly ILogger Log = LoggerFactoryResolver.Provider.CreateLogger("GodotUiFactory");
|
||||
|
||||
private IGodotUiRegistry _registry = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存池:uiKey -> 实例队列
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, Queue<IUiPageBehavior>> _cachedInstances = new();
|
||||
|
||||
/// <summary>
|
||||
/// 追踪所有创建的实例(用于清理)
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, HashSet<IUiPageBehavior>> _allInstances = new();
|
||||
|
||||
/// <summary>
|
||||
/// 根据指定的UI键创建UI页面实例
|
||||
/// 创建或获取UI页面实例
|
||||
/// </summary>
|
||||
/// <param name="uiKey">UI资源的唯一标识键</param>
|
||||
/// <returns>实现IUiPage接口的UI页面实例</returns>
|
||||
/// <exception cref="InvalidCastException">当UI场景没有继承IUiPage接口时抛出</exception>
|
||||
public IUiPageBehavior Create(string uiKey)
|
||||
public IUiPageBehavior GetOrCreate(string uiKey, UiInstancePolicy policy = UiInstancePolicy.AlwaysCreate)
|
||||
{
|
||||
// 从注册表中获取对应的场景资源
|
||||
var scene = _registry.Get(uiKey);
|
||||
|
||||
// 实例化场景节点
|
||||
var node = scene.Instantiate();
|
||||
|
||||
// 验证节点是否实现了IUiPageProvider接口
|
||||
if (node is not IUiPageBehaviorProvider provider)
|
||||
throw new InvalidCastException(
|
||||
$"UI scene {uiKey} must implement IUiPageBehaviorProvider");
|
||||
|
||||
// 获取并返回页面行为实例
|
||||
return provider.GetPage();
|
||||
return policy switch
|
||||
{
|
||||
UiInstancePolicy.Reuse => GetCachedOrCreate(uiKey),
|
||||
UiInstancePolicy.Pooled => GetFromPoolOrCreate(uiKey),
|
||||
_ => Create(uiKey)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化方法,获取UI注册表实例
|
||||
/// 仅创建新实例
|
||||
/// </summary>
|
||||
public IUiPageBehavior Create(string uiKey)
|
||||
{
|
||||
var scene = _registry.Get(uiKey);
|
||||
var node = scene.Instantiate();
|
||||
|
||||
if (node is not IUiPageBehaviorProvider provider)
|
||||
throw new InvalidCastException($"UI scene {uiKey} must implement IUiPageBehaviorProvider");
|
||||
|
||||
var page = provider.GetPage();
|
||||
|
||||
// 追踪实例
|
||||
if (!_allInstances.ContainsKey(uiKey))
|
||||
_allInstances[uiKey] = new HashSet<IUiPageBehavior>();
|
||||
_allInstances[uiKey].Add(page);
|
||||
|
||||
Log.Debug("Created new UI instance: {0}", uiKey);
|
||||
return page;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 预加载UI资源
|
||||
/// </summary>
|
||||
public void Preload(string uiKey, int count = 1)
|
||||
{
|
||||
Log.Debug("Preloading UI: {0}, count={1}", uiKey, count);
|
||||
|
||||
if (!_cachedInstances.ContainsKey(uiKey))
|
||||
_cachedInstances[uiKey] = new Queue<IUiPageBehavior>();
|
||||
|
||||
var queue = _cachedInstances[uiKey];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var instance = Create(uiKey);
|
||||
// 预加载的实例初始状态为隐藏
|
||||
instance.OnHide();
|
||||
queue.Enqueue(instance);
|
||||
}
|
||||
|
||||
Log.Debug("Preloaded {0} instances of {1}", count, uiKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量预加载
|
||||
/// </summary>
|
||||
public void PreloadBatch(params string[] uiKeys)
|
||||
{
|
||||
foreach (var uiKey in uiKeys)
|
||||
{
|
||||
Preload(uiKey);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 回收实例到缓存池
|
||||
/// </summary>
|
||||
public void Recycle(IUiPageBehavior page)
|
||||
{
|
||||
var uiKey = page.Key;
|
||||
|
||||
if (!_cachedInstances.ContainsKey(uiKey))
|
||||
_cachedInstances[uiKey] = new Queue<IUiPageBehavior>();
|
||||
|
||||
// 确保实例处于隐藏状态
|
||||
page.OnHide();
|
||||
|
||||
_cachedInstances[uiKey].Enqueue(page);
|
||||
Log.Debug("Recycled UI instance to pool: {0}, poolSize={1}", uiKey, _cachedInstances[uiKey].Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理指定UI的缓存
|
||||
/// </summary>
|
||||
public void ClearCache(string uiKey)
|
||||
{
|
||||
if (!_cachedInstances.TryGetValue(uiKey, out var queue))
|
||||
return;
|
||||
|
||||
int count = queue.Count;
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var instance = queue.Dequeue();
|
||||
DestroyInstance(instance);
|
||||
}
|
||||
|
||||
_cachedInstances.Remove(uiKey);
|
||||
Log.Debug("Cleared cache for UI: {0}, destroyed {1} instances", uiKey, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有缓存
|
||||
/// </summary>
|
||||
public void ClearAllCache()
|
||||
{
|
||||
foreach (var uiKey in _cachedInstances.Keys)
|
||||
{
|
||||
ClearCache(uiKey);
|
||||
}
|
||||
|
||||
Log.Debug("Cleared all UI caches");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否有缓存的实例
|
||||
/// </summary>
|
||||
public bool HasCached(string uiKey)
|
||||
{
|
||||
return _cachedInstances.TryGetValue(uiKey, out var queue) && queue.Count > 0;
|
||||
}
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
_registry = this.GetUtility<IGodotUiRegistry>()!;
|
||||
}
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// 获取缓存实例或创建新实例(Reuse策略)
|
||||
/// </summary>
|
||||
private IUiPageBehavior GetCachedOrCreate(string uiKey)
|
||||
{
|
||||
// 优先从缓存池获取
|
||||
if (_cachedInstances.TryGetValue(uiKey, out var queue) && queue.Count > 0)
|
||||
{
|
||||
var cached = queue.Dequeue();
|
||||
Log.Debug("Reused cached UI instance: {0}, remainingInPool={1}", uiKey, queue.Count);
|
||||
return cached;
|
||||
}
|
||||
|
||||
// 没有缓存则创建新实例
|
||||
Log.Debug("No cached instance, creating new: {0}", uiKey);
|
||||
return Create(uiKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从池中获取或创建(Pooled策略)
|
||||
/// 如果池为空,自动创建并填充
|
||||
/// </summary>
|
||||
private IUiPageBehavior GetFromPoolOrCreate(string uiKey)
|
||||
{
|
||||
// 如果池为空,先预加载一个
|
||||
if (HasCached(uiKey)) return GetCachedOrCreate(uiKey);
|
||||
Log.Debug("Pool empty, preloading instance: {0}", uiKey);
|
||||
Preload(uiKey);
|
||||
|
||||
return GetCachedOrCreate(uiKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 销毁实例
|
||||
/// </summary>
|
||||
private void DestroyInstance(IUiPageBehavior page)
|
||||
{
|
||||
var uiKey = page.Key;
|
||||
|
||||
// 从追踪列表移除
|
||||
if (_allInstances.TryGetValue(uiKey, out var set))
|
||||
{
|
||||
set.Remove(page);
|
||||
}
|
||||
|
||||
// 销毁Godot节点
|
||||
if (page.View is Node node)
|
||||
{
|
||||
node.QueueFreeX();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user