Skip to content

Commit

Permalink
perf(NativeFramePresenter): [Android] Don't detach pages in the backs…
Browse files Browse the repository at this point in the history
…tack

The behavior is now similar to the one from the iOS NativeFramePresenter, which keeps all pages loaded and stacked on top of each other. The behavior can be altered by using `FeatureConfiguration.NativeFramePresenter.AndroidUnloadInactivePages`, which is set to false by default.
  • Loading branch information
jeromelaban committed Dec 15, 2020
1 parent f38ccd3 commit 7253faf
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#if __ANDROID__
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Private.Infrastructure;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml;
using System.Threading.Tasks;
using System.Diagnostics;

namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls
{
[TestClass]
public class Given_NativeFrame
{
[TestMethod]
[RunsOnUIThread]
public async Task When_NavigateForward()
{
var style = Windows.UI.Xaml.Application.Current.Resources["NativeDefaultFrame"] as Style;
Assert.IsNotNull(style);

var SUT = new Frame() {
Style = style
};

TestServices.WindowHelper.WindowContent = SUT;

int GetAllMyPages()
=> SUT.EnumerateAllChildren(v => v is MyPage).Count();

/// Actively waiting for pages to be stacked is
/// required as NativeFramePresenter.UpdateStack awaits
/// for animations to finish, and there's no way to determine
/// from the Frame PoV that the animation is finished.
async Task WaitForPages(int count)
{
var sw = Stopwatch.StartNew();

while(sw.Elapsed < TimeSpan.FromSeconds(5))
{
await TestServices.WindowHelper.WaitForIdle();

if (GetAllMyPages() == count)
{
break;
}
}

Assert.AreEqual(count, GetAllMyPages());
}

await WaitForPages(0);

SUT.Navigate(typeof(MyPage));

await WaitForPages(1);

SUT.Navigate(typeof(MyPage));

await WaitForPages(2);

SUT.GoBack();

await WaitForPages(1);
}
}

partial class MyPage : Page
{
}
}
#endif
11 changes: 11 additions & 0 deletions src/Uno.UI/FeatureConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,17 @@ public static class ToolTip
public static int ShowDuration { get; set; } = 7000;
}

public static class NativeFramePresenter
{
#if __ANDROID__
/// <summary>
/// Determines if pages in the backstack are kept in the visual tree.
/// Defaults to false for performance considerations.
/// </summary>
public static bool AndroidUnloadInactivePages { get; set; } = false;
#endif
}

public static class UIElement
{
/// <summary>
Expand Down
9 changes: 6 additions & 3 deletions src/Uno.UI/NativeFramePresenter.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,16 @@ private async Task UpdateStack(PageStackEntry entry, NavigationEventArgs e)
await newPage.AnimateAsync(GetEnterAnimation());
newPage.ClearAnimation();
}
if (oldPage != null)
if (FeatureConfiguration.NativeFramePresenter.AndroidUnloadInactivePages && oldPage != null)
{
_pageStack.Children.Remove(oldPage);
}
break;
case NavigationMode.Back:
_pageStack.Children.Insert(0, newPage);
if (FeatureConfiguration.NativeFramePresenter.AndroidUnloadInactivePages)
{
_pageStack.Children.Insert(0, newPage);
}
if (GetIsAnimated(oldEntry))
{
await oldPage.AnimateAsync(GetExitAnimation());
Expand Down Expand Up @@ -233,4 +236,4 @@ private static Animation GetExitAnimation()
}
}
}
#endif
#endif

0 comments on commit 7253faf

Please sign in to comment.