From cd5de2c374ef76435a44320af62c3e6dd9e144da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=80=9D=E6=B5=B7?= <1464576565@qq.com> Date: Thu, 23 Apr 2026 20:19:46 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96UIService=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化UI模块更多细节容错处理 优化UI模块内存泄露问题 优化性能 --- Runtime/UI/Constant/UIHolderFactory.cs | 1 - Runtime/UI/Constant/UIMetaRegistry.cs | 114 +++++++++++------- Runtime/UI/Constant/UIMetadata.cs | 26 +++- Runtime/UI/Constant/UIMetadataObject.cs | 11 ++ Runtime/UI/Constant/UIResRegistry.cs | 51 ++++---- Runtime/UI/EventListenerProxy.cs | 3 + Runtime/UI/Manager/UIService.Block.cs | 8 +- Runtime/UI/Manager/UIService.Cache.cs | 18 ++- Runtime/UI/Manager/UIService.Open.cs | 14 ++- Runtime/UI/Manager/UIService.cs | 77 ++++++++++++ Runtime/UI/Other/IUITransitionPlayer.cs | 2 - Runtime/UI/Other/UIAnimationFlowTransition.cs | 1 - Runtime/UI/Other/UIPresetTransition.cs | 2 - Runtime/UI/UIBase/UIBase.Widget.cs | 51 ++++++-- Runtime/UI/UIBase/UIBase.cs | 4 +- Runtime/UI/UIBase/UIHolderObjectBase.cs | 47 ++------ Runtime/UI/UIBase/UITabWindow.cs | 16 +-- 17 files changed, 301 insertions(+), 145 deletions(-) diff --git a/Runtime/UI/Constant/UIHolderFactory.cs b/Runtime/UI/Constant/UIHolderFactory.cs index d422ab5..a42ea20 100644 --- a/Runtime/UI/Constant/UIHolderFactory.cs +++ b/Runtime/UI/Constant/UIHolderFactory.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using AlicizaX.Resource.Runtime; using AlicizaX; using Cysharp.Threading.Tasks; diff --git a/Runtime/UI/Constant/UIMetaRegistry.cs b/Runtime/UI/Constant/UIMetaRegistry.cs index a479041..cd359a5 100644 --- a/Runtime/UI/Constant/UIMetaRegistry.cs +++ b/Runtime/UI/Constant/UIMetaRegistry.cs @@ -1,11 +1,7 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; -using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; -using UnityEngine; -using UnityEngine.PlayerLoop; namespace AlicizaX.UI.Runtime { @@ -37,38 +33,36 @@ namespace AlicizaX.UI.Runtime [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Register(Type uiType, Type holderType, UILayer layer = UILayer.UI, bool fullScreen = false, int cacheTime = 0, bool needUpdate = false) { - var holderHandle = holderType.TypeHandle; - var uiHandle = uiType.TypeHandle; + RuntimeTypeHandle holderHandle = holderType.TypeHandle; + RuntimeTypeHandle uiHandle = uiType.TypeHandle; _typeHandleMap[uiHandle] = new UIMetaInfo(uiHandle, holderHandle, layer, fullScreen, cacheTime, needUpdate); _stringHandleMap[uiType.Name] = uiHandle; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryGet(RuntimeTypeHandle handle, out UIMetaInfo info) { if (_typeHandleMap.TryGetValue(handle, out info)) + { return true; + } - var t = Type.GetTypeFromHandle(handle); - - if (TryReflectAndRegister(t, out info)) - return true; - - return false; + return TryReflectAndRegister(Type.GetTypeFromHandle(handle), out info); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryGet(string typeName, out UIMetaInfo info) { - if (_stringHandleMap.TryGetValue(typeName, out var handle)) + if (_stringHandleMap.TryGetValue(typeName, out RuntimeTypeHandle handle)) + { return TryGet(handle, out info); + } - - var type = AlicizaX.Utility.Assembly.GetType(typeName); - + Type type = AlicizaX.Utility.Assembly.GetType(typeName); if (type != null && TryReflectAndRegister(type, out info)) + { return true; + } info = default; return false; @@ -77,7 +71,13 @@ namespace AlicizaX.UI.Runtime [MethodImpl(MethodImplOptions.NoInlining)] private static bool TryReflectAndRegister(Type uiType, out UIMetaInfo info) { - Log.Warning($"[UI] UI未注册[{uiType.FullName}] 反射进行缓存"); + if (uiType == null) + { + info = default; + return false; + } + + Log.Warning($"[UI] UI not pre-registered: {uiType.FullName}, using reflection fallback."); return TryReflectAndRegisterInternal(uiType, out info); } @@ -86,14 +86,11 @@ namespace AlicizaX.UI.Runtime { try { - Type baseType = uiType; -#pragma warning disable CS8632 - Type? holderType = null; - - var genericArgs = baseType.GetGenericArguments(); - if (genericArgs.Length > 0) + Type holderType = ResolveHolderType(uiType); + if (holderType == null) { - holderType = genericArgs[0]; + info = default; + return false; } UILayer layer = UILayer.UI; @@ -101,27 +98,38 @@ namespace AlicizaX.UI.Runtime int cacheTime = 0; bool needUpdate = false; - var windowAttribute = CustomAttributeData.GetCustomAttributes(uiType) - .FirstOrDefault(a => a.AttributeType.Name == nameof(WindowAttribute)); - var uiUpdateAttribute = CustomAttributeData.GetCustomAttributes(uiType) - .FirstOrDefault(a => a.AttributeType.Name == nameof(UIUpdateAttribute)); - - if (windowAttribute != null) + IList attributes = CustomAttributeData.GetCustomAttributes(uiType); + for (int i = 0; i < attributes.Count; i++) { - var args = windowAttribute.ConstructorArguments; - if (args.Count > 0) layer = (UILayer)(args[0].Value ?? UILayer.UI); - if (args.Count > 1) fullScreen = (bool)(args[1].Value ?? false); - if (args.Count > 2) cacheTime = (int)(args[2].Value ?? 0); + CustomAttributeData attribute = attributes[i]; + string attributeName = attribute.AttributeType.Name; + if (attributeName == nameof(WindowAttribute)) + { + IList args = attribute.ConstructorArguments; + if (args.Count > 0) + { + layer = (UILayer)(args[0].Value ?? UILayer.UI); + } + + if (args.Count > 1) + { + fullScreen = (bool)(args[1].Value ?? false); + } + + if (args.Count > 2) + { + cacheTime = (int)(args[2].Value ?? 0); + } + } + else if (attributeName == nameof(UIUpdateAttribute)) + { + needUpdate = true; + } } - needUpdate = uiUpdateAttribute != null; - - if (holderType != null) - { - Register(uiType, holderType, layer, fullScreen, cacheTime, needUpdate); - info = _typeHandleMap[uiType.TypeHandle]; - return true; - } + Register(uiType, holderType, layer, fullScreen, cacheTime, needUpdate); + info = _typeHandleMap[uiType.TypeHandle]; + return true; } catch (Exception ex) { @@ -131,5 +139,25 @@ namespace AlicizaX.UI.Runtime info = default; return false; } + + private static Type ResolveHolderType(Type uiType) + { + Type current = uiType; + while (current != null && current != typeof(object)) + { + if (current.IsGenericType) + { + Type[] genericArgs = current.GetGenericArguments(); + if (genericArgs.Length == 1 && typeof(UIHolderObjectBase).IsAssignableFrom(genericArgs[0])) + { + return genericArgs[0]; + } + } + + current = current.BaseType; + } + + return null; + } } } diff --git a/Runtime/UI/Constant/UIMetadata.cs b/Runtime/UI/Constant/UIMetadata.cs index a408447..586c462 100644 --- a/Runtime/UI/Constant/UIMetadata.cs +++ b/Runtime/UI/Constant/UIMetadata.cs @@ -35,6 +35,15 @@ namespace AlicizaX.UI.Runtime return; View = (UIBase)InstanceFactory.CreateInstanceOptimized(UILogicType); + EnsureCancellationToken(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void EnsureCancellationToken() + { + if (_cancellationTokenSource == null) + { _cancellationTokenSource = new CancellationTokenSource(); } } @@ -51,7 +60,7 @@ namespace AlicizaX.UI.Runtime DisposeAsync().Forget(); } - private async UniTask DisposeAsync() + internal async UniTask DisposeAsync() { CancelAsyncOperations(); @@ -64,11 +73,22 @@ namespace AlicizaX.UI.Runtime public UIMetadata(Type uiType) { + if (uiType == null) + { + throw new ArgumentNullException(nameof(uiType)); + } + UILogicType = uiType; - UIMetaRegistry.TryGet(UILogicType.TypeHandle, out MetaInfo); + if (!UIMetaRegistry.TryGet(UILogicType.TypeHandle, out MetaInfo)) + { + throw new InvalidOperationException($"[UI] Metadata not registered for {UILogicType.FullName}"); + } - UIResRegistry.TryGet(MetaInfo.HolderRuntimeTypeHandle, out ResInfo); + if (!UIResRegistry.TryGet(MetaInfo.HolderRuntimeTypeHandle, out ResInfo)) + { + throw new InvalidOperationException($"[UI] Resource metadata not registered for holder of {UILogicType.FullName}"); + } } } } diff --git a/Runtime/UI/Constant/UIMetadataObject.cs b/Runtime/UI/Constant/UIMetadataObject.cs index e39f14c..c635fd3 100644 --- a/Runtime/UI/Constant/UIMetadataObject.cs +++ b/Runtime/UI/Constant/UIMetadataObject.cs @@ -27,5 +27,16 @@ namespace AlicizaX.UI.Runtime { } } + + protected internal override void OnUnspawn() + { + base.OnUnspawn(); + + UIMetadata metadata = (UIMetadata)Target; + if (metadata != null) + { + metadata.CancelAsyncOperations(); + } + } } } diff --git a/Runtime/UI/Constant/UIResRegistry.cs b/Runtime/UI/Constant/UIResRegistry.cs index 3d468c6..3eb5d53 100644 --- a/Runtime/UI/Constant/UIResRegistry.cs +++ b/Runtime/UI/Constant/UIResRegistry.cs @@ -1,19 +1,12 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; -using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; -using UnityEditor; -using UnityEngine; namespace AlicizaX.UI.Runtime { public static class UIResRegistry { - private static readonly Dictionary _typeHandleMap = new(); - - public readonly struct UIResInfo { public readonly string Location; @@ -26,29 +19,35 @@ namespace AlicizaX.UI.Runtime LoadType = loadType; } } + + private static readonly Dictionary _typeHandleMap = new(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Register(Type holderType, string location, EUIResLoadType loadType) { - var handle = holderType.TypeHandle; + RuntimeTypeHandle handle = holderType.TypeHandle; _typeHandleMap[handle] = new UIResInfo(location, loadType); } public static bool TryGet(RuntimeTypeHandle handle, out UIResInfo info) { if (_typeHandleMap.TryGetValue(handle, out info)) + { return true; + } - var t = Type.GetTypeFromHandle(handle); - - if (TryReflectAndRegister(t, out info)) - return true; - - return false; + return TryReflectAndRegister(Type.GetTypeFromHandle(handle), out info); } [MethodImpl(MethodImplOptions.NoInlining)] private static bool TryReflectAndRegister(Type holderType, out UIResInfo info) { + if (holderType == null) + { + info = default; + return false; + } + return TryReflectAndRegisterInternal(holderType, out info); } @@ -57,17 +56,21 @@ namespace AlicizaX.UI.Runtime { try { - var cad = CustomAttributeData.GetCustomAttributes(holderType) - .FirstOrDefault(a => a.AttributeType.Name == nameof(UIResAttribute)); - - string resLocation = string.Empty; - EUIResLoadType resLoadType = EUIResLoadType.AssetBundle; - - if (cad != null) + IList attributes = CustomAttributeData.GetCustomAttributes(holderType); + for (int i = 0; i < attributes.Count; i++) { - var args = cad.ConstructorArguments; - if (args.Count > 0) resLocation = (string)(args[0].Value ?? string.Empty); - if (args.Count > 1) resLoadType = (EUIResLoadType)(args[1].Value ?? EUIResLoadType.AssetBundle); + CustomAttributeData attribute = attributes[i]; + if (attribute.AttributeType.Name != nameof(UIResAttribute)) + { + continue; + } + + IList args = attribute.ConstructorArguments; + string resLocation = args.Count > 0 ? (string)(args[0].Value ?? string.Empty) : string.Empty; + EUIResLoadType resLoadType = args.Count > 1 + ? (EUIResLoadType)(args[1].Value ?? EUIResLoadType.AssetBundle) + : EUIResLoadType.AssetBundle; + Register(holderType, resLocation, resLoadType); info = _typeHandleMap[holderType.TypeHandle]; return true; diff --git a/Runtime/UI/EventListenerProxy.cs b/Runtime/UI/EventListenerProxy.cs index 487a748..1943490 100644 --- a/Runtime/UI/EventListenerProxy.cs +++ b/Runtime/UI/EventListenerProxy.cs @@ -37,7 +37,10 @@ namespace AlicizaX public void Clear() { for (int i = _eventHandles.Count - 1; i >= 0; i--) + { _eventHandles[i].Dispose(); + } + _eventHandles.Clear(); } } diff --git a/Runtime/UI/Manager/UIService.Block.cs b/Runtime/UI/Manager/UIService.Block.cs index ef627fa..0a50d99 100644 --- a/Runtime/UI/Manager/UIService.Block.cs +++ b/Runtime/UI/Manager/UIService.Block.cs @@ -27,13 +27,14 @@ namespace AlicizaX.UI.Runtime /// 倒计时/s public void SetUIBlock(float timeDuration) { + ITimerService timerService = GetTimerService(); if (m_LastCountDownGuid != 0) { - _timerService.RemoveTimer(m_LastCountDownGuid); + timerService.RemoveTimer(m_LastCountDownGuid); } SetLayerBlockOption(true); - m_LastCountDownGuid = _timerService.AddTimer(OnBlockCountDown, timeDuration); + m_LastCountDownGuid = timerService.AddTimer(OnBlockCountDown, timeDuration); } /// @@ -41,9 +42,10 @@ namespace AlicizaX.UI.Runtime /// public void ForceExitBlock() { + ITimerService timerService = GetTimerService(); if (m_LastCountDownGuid != 0) { - _timerService.RemoveTimer(m_LastCountDownGuid); + timerService.RemoveTimer(m_LastCountDownGuid); } RecoverLayerOptionAll(); diff --git a/Runtime/UI/Manager/UIService.Cache.cs b/Runtime/UI/Manager/UIService.Cache.cs index 93ebda7..e1e5a14 100644 --- a/Runtime/UI/Manager/UIService.Cache.cs +++ b/Runtime/UI/Manager/UIService.Cache.cs @@ -40,7 +40,8 @@ namespace AlicizaX.UI.Runtime uiMetadata.View.Holder.transform.SetParent(UICacheLayer); if (uiMetadata.MetaInfo.CacheTime > 0) { - timerId = _timerService.AddTimer( + ITimerService timerService = GetTimerService(); + timerId = timerService.AddTimer( OnTimerDisposeWindow, uiMetadata, uiMetadata.MetaInfo.CacheTime, @@ -62,8 +63,8 @@ namespace AlicizaX.UI.Runtime { if (meta != null) { - meta.Dispose(); RemoveFromCache(meta.MetaInfo.RuntimeTypeHandle); + meta.Dispose(); } } @@ -73,11 +74,22 @@ namespace AlicizaX.UI.Runtime { m_CacheWindow.Remove(typeHandle); entry.Metadata.InCache = false; - if (entry.TimerId > 0) + if (entry.TimerId > 0 && _timerService != null) { _timerService.RemoveTimer(entry.TimerId); } } } + + private ITimerService GetTimerService() + { + if (_timerService != null) + { + return _timerService; + } + + _timerService = AppServices.Require(); + return _timerService; + } } } diff --git a/Runtime/UI/Manager/UIService.Open.cs b/Runtime/UI/Manager/UIService.Open.cs index a8bdf08..e874997 100644 --- a/Runtime/UI/Manager/UIService.Open.cs +++ b/Runtime/UI/Manager/UIService.Open.cs @@ -28,6 +28,7 @@ namespace AlicizaX.UI.Runtime private async UniTask ShowUIImplAsync(UIMetadata metaInfo, params object[] userDatas) { CreateMetaUI(metaInfo); + EnsureMetaCanOpen(metaInfo); await UIHolderFactory.CreateUIResourceAsync(metaInfo, UICacheLayer); if (metaInfo.View == null || metaInfo.State == UIState.Uninitialized || metaInfo.State == UIState.Destroyed) { @@ -42,6 +43,7 @@ namespace AlicizaX.UI.Runtime private UIBase ShowUIImplSync(UIMetadata metaInfo, params object[] userDatas) { CreateMetaUI(metaInfo); + EnsureMetaCanOpen(metaInfo); UIHolderFactory.CreateUIResourceSync(metaInfo, UICacheLayer); if (metaInfo.View == null || metaInfo.State == UIState.Uninitialized || metaInfo.State == UIState.Destroyed) { @@ -63,7 +65,7 @@ namespace AlicizaX.UI.Runtime if (meta.State == UIState.CreatedUI) { meta.CancelAsyncOperations(); - meta.Dispose(); + await meta.DisposeAsync(); return; } @@ -79,6 +81,7 @@ namespace AlicizaX.UI.Runtime } meta.CancelAsyncOperations(); + meta.EnsureCancellationToken(); await meta.View.InternalClose(); if (meta.State != UIState.Closed) { @@ -103,6 +106,15 @@ namespace AlicizaX.UI.Runtime if (meta.State == UIState.Uninitialized) meta.CreateUI(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void EnsureMetaCanOpen(UIMetadata meta) + { + if (meta.State == UIState.Closed) + { + meta.EnsureCancellationToken(); + } + } + private void FinalizeShow(UIMetadata meta, object[] userDatas) { diff --git a/Runtime/UI/Manager/UIService.cs b/Runtime/UI/Manager/UIService.cs index 56a071f..e61e2c0 100644 --- a/Runtime/UI/Manager/UIService.cs +++ b/Runtime/UI/Manager/UIService.cs @@ -17,6 +17,7 @@ namespace AlicizaX.UI.Runtime protected override void OnDestroyService() { + DestroyAllManagedUI().Forget(); } void IServiceTickable.Tick(float deltaTime) @@ -99,5 +100,81 @@ namespace AlicizaX.UI.Runtime { _timerService = timerService; } + + private async UniTask DestroyAllManagedUI() + { + for (int layerIndex = 0; layerIndex < _openUI.Length; layerIndex++) + { + LayerData layer = _openUI[layerIndex]; + if (layer == null) + { + continue; + } + + int count = layer.OrderList.Count; + for (int i = count - 1; i >= 0; i--) + { + UIMetadata meta = layer.OrderList[i]; + if (meta == null) + { + continue; + } + + meta.CancelAsyncOperations(); + await meta.DisposeAsync(); + } + + layer.OrderList.Clear(); + layer.IndexMap.Clear(); + layer.LastFullscreenIndex = -1; + } + + if (m_CacheWindow.Count > 0) + { + RuntimeTypeHandle[] handles = new RuntimeTypeHandle[m_CacheWindow.Count]; + int writeIndex = 0; + foreach (var pair in m_CacheWindow) + { + handles[writeIndex++] = pair.Key; + } + + for (int i = 0; i < writeIndex; i++) + { + if (!m_CacheWindow.TryGetValue(handles[i], out CacheEntry entry)) + { + continue; + } + + if (entry.TimerId > 0 && _timerService != null) + { + _timerService.RemoveTimer(entry.TimerId); + } + + entry.Metadata.InCache = false; + entry.Metadata.CancelAsyncOperations(); + await entry.Metadata.DisposeAsync(); + } + + m_CacheWindow.Clear(); + } + + if (m_LastCountDownGuid != 0 && _timerService != null) + { + _timerService.RemoveTimer(m_LastCountDownGuid); + m_LastCountDownGuid = 0; + } + + if (m_LayerBlock != null) + { + UnityEngine.Object.Destroy(m_LayerBlock); + m_LayerBlock = null; + } + + UICacheLayer = null; + UICanvasRoot = null; + UICanvas = null; + UICamera = null; + UIRoot = null; + } } } diff --git a/Runtime/UI/Other/IUITransitionPlayer.cs b/Runtime/UI/Other/IUITransitionPlayer.cs index bf12163..e2b9e2b 100644 --- a/Runtime/UI/Other/IUITransitionPlayer.cs +++ b/Runtime/UI/Other/IUITransitionPlayer.cs @@ -5,8 +5,6 @@ namespace AlicizaX.UI.Runtime { public interface IUITransitionPlayer { - int Priority { get; } - UniTask PlayOpenAsync(CancellationToken cancellationToken = default); UniTask PlayCloseAsync(CancellationToken cancellationToken = default); diff --git a/Runtime/UI/Other/UIAnimationFlowTransition.cs b/Runtime/UI/Other/UIAnimationFlowTransition.cs index 4987f41..16f9422 100644 --- a/Runtime/UI/Other/UIAnimationFlowTransition.cs +++ b/Runtime/UI/Other/UIAnimationFlowTransition.cs @@ -8,7 +8,6 @@ namespace AlicizaX.UI.Runtime [DisallowMultipleComponent] public sealed class UIAnimationFlowTransition : AnimationFlow.Runtime.AnimationFlow, IUITransitionPlayer { - public int Priority => 0; [SerializeField] private string openClip = "Open"; [SerializeField] private string closeClip = "Close"; diff --git a/Runtime/UI/Other/UIPresetTransition.cs b/Runtime/UI/Other/UIPresetTransition.cs index 3a2abad..39cf9fe 100644 --- a/Runtime/UI/Other/UIPresetTransition.cs +++ b/Runtime/UI/Other/UIPresetTransition.cs @@ -38,8 +38,6 @@ namespace AlicizaX.UI.Runtime public float Alpha; } - public int Priority => 100; - [SerializeField] private UITransitionPreset openPreset = UITransitionPreset.FadeScale; [SerializeField] private UITransitionPreset closePreset = UITransitionPreset.FadeScale; [SerializeField] private UITransitionEase openEase = UITransitionEase.OutCubic; diff --git a/Runtime/UI/UIBase/UIBase.Widget.cs b/Runtime/UI/UIBase/UIBase.Widget.cs index 5bcff00..383cc88 100644 --- a/Runtime/UI/UIBase/UIBase.Widget.cs +++ b/Runtime/UI/UIBase/UIBase.Widget.cs @@ -5,7 +5,6 @@ using System.Threading; using AlicizaX; using Cysharp.Threading.Tasks; using UnityEngine; -using UnityEngine.Pool; namespace AlicizaX.UI.Runtime { @@ -39,8 +38,17 @@ namespace AlicizaX.UI.Runtime for (int j = 0; j < i; j++) { - if (temp[j].View.Visible) await temp[j].View.InternalClose(); - temp[j].Dispose(); + UIMetadata metadata = temp[j]; + if (metadata.View.Visible) + { + metadata.CancelAsyncOperations(); + metadata.EnsureCancellationToken(); + await metadata.View.InternalClose(metadata.CancellationToken); + } + + await metadata.DisposeAsync(); + UIMetadataFactory.ReturnToPool(metadata); + temp[j] = null; } } finally @@ -54,9 +62,9 @@ namespace AlicizaX.UI.Runtime private void ChildVisible(bool value) { - foreach (var kvp in _children) + foreach (KeyValuePair kvp in _children) { - var view = kvp.Value.View; + UIBase view = kvp.Value.View; if (view.State == UIState.Opened) { view.Visible = value; @@ -142,7 +150,13 @@ namespace AlicizaX.UI.Runtime private async UniTask ProcessWidget(UIMetadata meta, bool visible, CancellationToken cancellationToken = default) { - if (!AddWidget(meta)) return; + if (!AddWidget(meta)) + { + await meta.DisposeAsync(); + UIMetadataFactory.ReturnToPool(meta); + return; + } + await meta.View.InternalInitlized(cancellationToken); meta.View.Visible = visible; if (meta.View.Visible) @@ -156,8 +170,6 @@ namespace AlicizaX.UI.Runtime if (!_children.TryAdd(meta.View, meta)) { Log.Warning("Already has widget:{0}", meta.View); - meta.Dispose(); - UIMetadataFactory.ReturnToPool(meta); return false; } @@ -174,16 +186,33 @@ namespace AlicizaX.UI.Runtime if (_children.Remove(widget, out var meta)) { meta.CancelAsyncOperations(); - await widget.InternalClose(); + meta.EnsureCancellationToken(); + await widget.InternalClose(meta.CancellationToken); if (meta.MetaInfo.NeedUpdate) { - _updateableChildren.Remove(meta); + RemoveUpdateableChild(meta); } - meta.Dispose(); + await meta.DisposeAsync(); UIMetadataFactory.ReturnToPool(meta); } } + + private void RemoveUpdateableChild(UIMetadata meta) + { + for (int i = 0; i < _updateableChildren.Count; i++) + { + if (_updateableChildren[i] != meta) + { + continue; + } + + int lastIndex = _updateableChildren.Count - 1; + _updateableChildren[i] = _updateableChildren[lastIndex]; + _updateableChildren.RemoveAt(lastIndex); + return; + } + } } } diff --git a/Runtime/UI/UIBase/UIBase.cs b/Runtime/UI/UIBase/UIBase.cs index 28ee541..5cc464d 100644 --- a/Runtime/UI/UIBase/UIBase.cs +++ b/Runtime/UI/UIBase/UIBase.cs @@ -16,7 +16,6 @@ namespace AlicizaX.UI.Runtime _state = UIState.CreatedUI; } - ~UIBase() => Dispose(false); private bool _disposed; internal Canvas _canvas; @@ -105,7 +104,6 @@ namespace AlicizaX.UI.Runtime public void Dispose() { Dispose(true); - GC.SuppressFinalize(this); } private void Dispose(bool disposing) @@ -190,7 +188,7 @@ namespace AlicizaX.UI.Runtime private void ReleaseEventListenerProxy() { - if (!_eventListenerProxy.IsNull()) + if (_eventListenerProxy != null) { MemoryPool.Release(_eventListenerProxy); _eventListenerProxy = null; diff --git a/Runtime/UI/UIBase/UIHolderObjectBase.cs b/Runtime/UI/UIBase/UIHolderObjectBase.cs index f2c83c2..c94a885 100644 --- a/Runtime/UI/UIBase/UIHolderObjectBase.cs +++ b/Runtime/UI/UIBase/UIHolderObjectBase.cs @@ -1,4 +1,5 @@ -using System; +using System; +using System.Collections.Generic; using System.Threading; using Cysharp.Threading.Tasks; using UnityEngine; @@ -6,7 +7,7 @@ using UnityEngine; namespace AlicizaX.UI.Runtime { [DisallowMultipleComponent] - public abstract class UIHolderObjectBase : UnityEngine.MonoBehaviour + public abstract class UIHolderObjectBase : MonoBehaviour { public Action OnWindowInitEvent; public Action OnWindowBeforeShowEvent; @@ -17,30 +18,17 @@ namespace AlicizaX.UI.Runtime private GameObject _target; private IUITransitionPlayer _transitionPlayer; - - /// - /// UI实例资源对象。 - /// public GameObject Target => _target ??= gameObject; private RectTransform _rectTransform; + public RectTransform RectTransform => _rectTransform ??= Target.transform as RectTransform; - /// - /// 窗口矩阵位置组件。 - /// - public RectTransform RectTransform => _rectTransform ??= _target.transform as RectTransform; - - /// - /// 可见性 - /// public bool Visible { get => Target.activeSelf; - - internal set { _target.SetActive(value); } + internal set => Target.SetActive(value); } - public virtual void Awake() { _target = gameObject; @@ -55,21 +43,21 @@ namespace AlicizaX.UI.Runtime internal UniTask PlayOpenTransitionAsync(CancellationToken cancellationToken = default) { - return TryGetTransitionPlayer(out var transitionPlayer) + return TryGetTransitionPlayer(out IUITransitionPlayer transitionPlayer) ? transitionPlayer.PlayOpenAsync(cancellationToken) : UniTask.CompletedTask; } internal UniTask PlayCloseTransitionAsync(CancellationToken cancellationToken = default) { - return TryGetTransitionPlayer(out var transitionPlayer) + return TryGetTransitionPlayer(out IUITransitionPlayer transitionPlayer) ? transitionPlayer.PlayCloseAsync(cancellationToken) : UniTask.CompletedTask; } internal void StopTransition() { - if (TryGetTransitionPlayer(out var transitionPlayer)) + if (TryGetTransitionPlayer(out IUITransitionPlayer transitionPlayer)) { transitionPlayer.Stop(); } @@ -83,24 +71,7 @@ namespace AlicizaX.UI.Runtime return true; } - _transitionPlayer = null; - int bestPriority = int.MinValue; - MonoBehaviour[] behaviours = GetComponents(); - for (int i = 0; i < behaviours.Length; i++) - { - MonoBehaviour behaviour = behaviours[i]; - if (behaviours.IsNull() || !behaviour.isActiveAndEnabled || behaviour is not IUITransitionPlayer player) - { - continue; - } - - if (player.Priority > bestPriority) - { - _transitionPlayer = player; - bestPriority = player.Priority; - } - } - + _transitionPlayer = GetComponent(); transitionPlayer = _transitionPlayer; return transitionPlayer != null; } diff --git a/Runtime/UI/UIBase/UITabWindow.cs b/Runtime/UI/UIBase/UITabWindow.cs index 93a62bc..14a8e5f 100644 --- a/Runtime/UI/UIBase/UITabWindow.cs +++ b/Runtime/UI/UIBase/UITabWindow.cs @@ -58,8 +58,7 @@ namespace AlicizaX.UI.Runtime // 初始化方法(泛型版本) protected void InitTabVirtuallyView(Transform parent = null) where TTab : UIWidget { - var metadata = UIMetadataFactory.GetWindowMetadata(); - CacheTabMetadata(metadata, parent); + CacheTabMetadata(typeof(TTab).TypeHandle, parent); } // 初始化方法(类型名版本) @@ -67,15 +66,12 @@ namespace AlicizaX.UI.Runtime { if (UIMetaRegistry.TryGet(typeName, out var metaRegistry)) { - var metadata = UIMetadataFactory.GetWindowMetadata(metaRegistry.RuntimeTypeHandle); - CacheTabMetadata(metadata, parent); + CacheTabMetadata(metaRegistry.RuntimeTypeHandle, parent); } } - private void CacheTabMetadata(UIMetadata metadata, Transform parent) + private void CacheTabMetadata(RuntimeTypeHandle typeHandle, Transform parent) { - var typeHandle = metadata.MetaInfo.RuntimeTypeHandle; - if (!_tabCache.ContainsKey(typeHandle)) { _typeOrder.Add(typeHandle); @@ -105,10 +101,10 @@ namespace AlicizaX.UI.Runtime try { - var metadata = UIMetadataFactory.GetWindowMetadata(typeHandle); - var parent = _tabCache[typeHandle]; + UIMetadata metadata = UIMetadataFactory.GetWidgetMetadata(typeHandle); + Transform parent = _tabCache[typeHandle]; - var widget = await CreateWidgetUIAsync(metadata, parent, false); + UIBase widget = await CreateWidgetUIAsync(metadata, parent, false); if (widget is not UIWidget tabWidget) return; _loadedTabs[typeHandle] = tabWidget;