diff --git a/src/Core/src/Platform/Android/MauiWindowInsetListener.cs b/src/Core/src/Platform/Android/MauiWindowInsetListener.cs index 3e1d2509d4c5..97f4c9e9de19 100644 --- a/src/Core/src/Platform/Android/MauiWindowInsetListener.cs +++ b/src/Core/src/Platform/Android/MauiWindowInsetListener.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using Android.Content; using Android.Views; using AndroidX.Core.Graphics; @@ -12,11 +13,6 @@ namespace Microsoft.Maui.Platform { - /// - /// Registry entry for tracking view instances and their associated listeners. - /// Uses WeakReference to avoid memory leaks when views are disposed. - /// - internal record ViewEntry(WeakReference View, MauiWindowInsetListener Listener); /// /// Manages window insets and safe area handling for Android views. @@ -36,8 +32,9 @@ internal class MauiWindowInsetListener : WindowInsetsAnimationCompat.Callback, I // Static tracking for views that have local inset listeners. // This registry allows child views to find their appropriate listener without // relying on a global activity-level listener. + // Uses ConditionalWeakTable for O(1) lookup and automatic cleanup. // Thread Safety: All access must be on UI thread (enforced by Android's threading model). - static readonly List _registeredViews = new(); + static readonly ConditionalWeakTable _registeredViews = new(); /// /// Registers a view to use this local listener instead of the global one. @@ -47,23 +44,7 @@ internal class MauiWindowInsetListener : WindowInsetsAnimationCompat.Callback, I /// The view to register internal void RegisterView(AView view) { - // Clean up dead references and check for existing registration - for (int i = _registeredViews.Count - 1; i >= 0; i--) - { - var entry = _registeredViews[i]; - if (!entry.View.TryGetTarget(out var existingView)) - { - _registeredViews.RemoveAt(i); - } - else if (existingView == view) - { - // Already registered, no need to add again - return; - } - } - - // Add this view to the registry - _registeredViews.Add(new ViewEntry(new WeakReference(view), this)); + _registeredViews.AddOrUpdate(view, this); } /// @@ -73,14 +54,10 @@ internal void RegisterView(AView view) /// The view to unregister internal static MauiWindowInsetListener? UnregisterView(AView view) { - for (int i = _registeredViews.Count - 1; i >= 0; i--) + if (_registeredViews.TryGetValue(view, out var listener)) { - if (_registeredViews[i].View.TryGetTarget(out var registeredView) && registeredView == view) - { - var listener = _registeredViews[i].Listener; - _registeredViews.RemoveAt(i); - return listener; - } + _registeredViews.Remove(view); + return listener; } return null; } @@ -107,22 +84,9 @@ internal void RegisterView(AView view) return null; } - if (parent is AView parentView) + if (parent is AView parentView && _registeredViews.TryGetValue(parentView, out var listener)) { - // Check if this parent view is registered - // Clean up dead references while searching - for (int i = _registeredViews.Count - 1; i >= 0; i--) - { - var entry = _registeredViews[i]; - if (!entry.View.TryGetTarget(out var registeredView)) - { - _registeredViews.RemoveAt(i); - } - else if (ReferenceEquals(registeredView, parentView)) - { - return entry.Listener; - } - } + return listener; } parent = parent.Parent;