Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Commit d59f34f

Browse files
authored
[Android] Fix content pages not Garbage collected (#14717)
* Create test to prove that navigated-from content pages are not garbage collected when using Shell issue #14657 * Fix disposing Shell objects removing drawer listener (_drawerToggle) allows shell pages to be collected by GC issue #14657 * Correctly dispose views Shell TitleView is explicitly set to null, because otherwise pages would not be disposed of. Also views are explicitly removed during disposal. issue #14657
1 parent e95006e commit d59f34f

File tree

5 files changed

+154
-1
lines changed

5 files changed

+154
-1
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
using Xamarin.Forms.CustomAttributes;
2+
using Xamarin.Forms.Internals;
3+
using System;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
7+
#if UITEST
8+
using Xamarin.Forms.Core.UITests;
9+
using Xamarin.UITest;
10+
using NUnit.Framework;
11+
#endif
12+
13+
namespace Xamarin.Forms.Controls.Issues
14+
{
15+
#if UITEST
16+
[Category(UITestCategories.Github10000)]
17+
[Category(UITestCategories.Shell)]
18+
[Category(UITestCategories.TitleView)]
19+
#endif
20+
[Preserve(AllMembers = true)]
21+
[Issue(IssueTracker.Github, 14657, "Shell pages are not released from memory", PlatformAffected.Android)]
22+
public class Issue14657 : TestShell
23+
{
24+
static int pageCount = 0;
25+
protected override void Init()
26+
{
27+
Routing.RegisterRoute(nameof(Issue14657_ChildPage), typeof(Issue14657_ChildPage));
28+
29+
var rootPage = CreateRootPage();
30+
31+
AddContentPage(rootPage);
32+
}
33+
34+
ContentPage CreateRootPage()
35+
{
36+
var rootPage = CreateContentPage("Home page");
37+
rootPage.Content = new StackLayout()
38+
{
39+
Children =
40+
{
41+
new Button()
42+
{
43+
Command = new Command(CollectMemory),
44+
Text = "Force GC",
45+
AutomationId = "GC_14657"
46+
},
47+
new Button()
48+
{
49+
Command = new Command(async () => await GoToChild()),
50+
Text = "Go to child page",
51+
AutomationId = "GoToChild_14657"
52+
}
53+
}
54+
};
55+
Shell.SetTitleView(rootPage, new StackLayout()
56+
{
57+
Orientation = StackOrientation.Horizontal,
58+
Children = { new Label { Text = "Root Page" } }
59+
});
60+
61+
return rootPage;
62+
}
63+
64+
public class Issue14657_ChildPage : ContentPage
65+
{
66+
public Issue14657_ChildPage()
67+
{
68+
Interlocked.Increment(ref pageCount);
69+
70+
Content = new StackLayout
71+
{
72+
Children =
73+
{
74+
new Label()
75+
{
76+
Text = $"{pageCount}",
77+
AutomationId = "CountLabel",
78+
TextColor = Color.Black
79+
},
80+
new Button()
81+
{
82+
Command = new Command(CollectMemory),
83+
Text = "Force GC",
84+
AutomationId = "GC_14657"
85+
}
86+
}
87+
};
88+
}
89+
90+
~Issue14657_ChildPage()
91+
{
92+
Interlocked.Decrement(ref pageCount);
93+
}
94+
}
95+
96+
async Task GoToChild()
97+
{
98+
await GoToAsync(nameof(Issue14657_ChildPage));
99+
}
100+
101+
static void CollectMemory()
102+
{
103+
GC.Collect();
104+
GC.WaitForPendingFinalizers();
105+
GC.WaitForPendingFinalizers();
106+
GC.Collect();
107+
GC.WaitForPendingFinalizers();
108+
GC.WaitForPendingFinalizers();
109+
GC.Collect();
110+
}
111+
112+
#if UITEST
113+
[Test]
114+
public void Issue14657Test()
115+
{
116+
RunningApp.Tap("GoToChild_14657");
117+
RunningApp.WaitForFirstElement("CountLabel")
118+
.AssertHasText("1");
119+
RunningApp.NavigateBack();
120+
RunningApp.Tap("GC_14657");
121+
122+
RunningApp.Tap("GoToChild_14657");
123+
RunningApp.WaitForFirstElement("CountLabel")
124+
.AssertHasText("1");
125+
RunningApp.NavigateBack();
126+
RunningApp.Tap("GC_14657");
127+
128+
RunningApp.Tap("GoToChild_14657");
129+
RunningApp.WaitForFirstElement("CountLabel")
130+
.AssertHasText("1");
131+
RunningApp.NavigateBack();
132+
}
133+
134+
#endif
135+
}
136+
}

Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,7 @@
973973
<SubType>Code</SubType>
974974
</Compile>
975975
<Compile Include="$(MSBuildThisFileDirectory)Issue14544.cs" />
976+
<Compile Include="$(MSBuildThisFileDirectory)Issue14657.cs" />
976977
<Compile Include="$(MSBuildThisFileDirectory)_TemplateMarkup.xaml.cs">
977978
<DependentUpon>_TemplateMarkup.xaml</DependentUpon>
978979
<SubType>Code</SubType>

Xamarin.Forms.Platform.Android/Renderers/ContainerView.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ protected override void Dispose(bool disposing)
5252

5353
if (disposing)
5454
{
55+
RemoveAllViews();
5556
_shellViewRenderer?.TearDown();
5657
_view = null;
5758
}

Xamarin.Forms.Platform.Android/Renderers/ShellContentFragment.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,15 @@ public override AView OnCreateView(LayoutInflater inflater, ViewGroup container,
165165

166166
void Destroy()
167167
{
168+
if (_page != null)
169+
{
170+
var titleView = Shell.GetTitleView(_page);
171+
if (titleView != null)
172+
{
173+
Shell.SetTitleView(_page, null);
174+
}
175+
}
176+
168177
((IShellController)_shellContext.Shell).RemoveAppearanceObserver(this);
169178

170179
if (_shellContent != null)
@@ -180,6 +189,8 @@ void Destroy()
180189

181190
if (_root is ViewGroup vg)
182191
vg.RemoveView(_shellPageContainer);
192+
193+
_shellPageContainer.Dispose();
183194
}
184195

185196
_renderer?.Dispose();
@@ -194,6 +205,7 @@ void Destroy()
194205
_root = null;
195206
_renderer = null;
196207
_shellContent = null;
208+
_shellPageContainer = null;
197209
}
198210

199211
protected override void Dispose(bool disposing)
@@ -223,4 +235,4 @@ public override void OnDestroy()
223235

224236
protected virtual void SetAppearance(ShellAppearance appearance) => _appearanceTracker.SetAppearance(_toolbar, _toolbarTracker, appearance);
225237
}
226-
}
238+
}

Xamarin.Forms.Platform.Android/Renderers/ShellToolbarTracker.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,10 @@ protected override void Dispose(bool disposing)
176176
_currentMenuItems?.Clear();
177177
_currentToolbarItems?.Clear();
178178

179+
_drawerLayout.RemoveDrawerListener(_drawerToggle);
179180
_drawerToggle?.Dispose();
181+
182+
_toolbar.RemoveAllViews();
180183
}
181184

182185
_currentMenuItems = null;

0 commit comments

Comments
 (0)