[Android] Handle fragment removal inside of the RemovePage method (#1053)
* Repro * Handle fragment removal inside of RemovePage method * Fix class name for test * Split long strings
This commit is contained in:
Родитель
7b69ea969a
Коммит
6de1c5c8d7
|
@ -0,0 +1,86 @@
|
|||
using Xamarin.Forms.CustomAttributes;
|
||||
using Xamarin.Forms.Internals;
|
||||
|
||||
#if UITEST
|
||||
using Xamarin.UITest;
|
||||
using NUnit.Framework;
|
||||
using Xamarin.Forms.Core.UITests;
|
||||
#endif
|
||||
|
||||
namespace Xamarin.Forms.Controls.Issues
|
||||
{
|
||||
#if UITEST
|
||||
[Category(UITestCategories.Navigation)]
|
||||
#endif
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.None, 0101100101,
|
||||
"PopAsync crashing after RemovePage when support packages are updated to 25.1.1",
|
||||
PlatformAffected.Android)]
|
||||
public class PopAfterRemove : TestNavigationPage
|
||||
{
|
||||
ContentPage _intermediate1;
|
||||
ContentPage _intermediate2;
|
||||
|
||||
protected override async void Init()
|
||||
{
|
||||
_intermediate1 = Intermediate();
|
||||
_intermediate2 = Intermediate();
|
||||
|
||||
await PushAsync(Root());
|
||||
await PushAsync(_intermediate1);
|
||||
await PushAsync(_intermediate2);
|
||||
await PushAsync(Last());
|
||||
}
|
||||
|
||||
const string StartTest = "Start Test";
|
||||
const string RootLabel = "Root";
|
||||
|
||||
ContentPage Last()
|
||||
{
|
||||
var test = new Button { Text = StartTest };
|
||||
|
||||
var instructions = new Label
|
||||
{
|
||||
Text =
|
||||
$"Tap the button labeled '{StartTest}'. The app should navigate to a page displaying the label "
|
||||
+ $"'{RootLabel}'. If the application crashes, the test has failed."
|
||||
};
|
||||
|
||||
var layout = new StackLayout();
|
||||
|
||||
layout.Children.Add(instructions);
|
||||
layout.Children.Add(test);
|
||||
|
||||
test.Clicked += (sender, args) =>
|
||||
{
|
||||
Navigation.RemovePage(_intermediate2);
|
||||
Navigation.RemovePage(_intermediate1);
|
||||
|
||||
Navigation.PopAsync(true);
|
||||
};
|
||||
|
||||
return new ContentPage { Content = layout };
|
||||
}
|
||||
|
||||
static ContentPage Root()
|
||||
{
|
||||
return new ContentPage { Content = new Label { Text = RootLabel } };
|
||||
}
|
||||
|
||||
static ContentPage Intermediate()
|
||||
{
|
||||
return new ContentPage { Content = new Label { Text = "Page" } };
|
||||
}
|
||||
|
||||
#if UITEST
|
||||
[Test]
|
||||
public void PopAsyncAfterRemovePageDoesNotCrash()
|
||||
{
|
||||
RunningApp.WaitForElement(StartTest);
|
||||
RunningApp.Tap(StartTest);
|
||||
RunningApp.WaitForElement(RootLabel);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -271,6 +271,7 @@
|
|||
<DependentUpon>PlatformSpecifics_iOSTranslucentNavBarX.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)PopAfterRemove.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)TestPages\ScreenshotConditionalApp.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla41842.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla42277.cs" />
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
public const string InputTransparent = "InputTransparent";
|
||||
public const string IsEnabled = "IsEnabled";
|
||||
public const string Gestures = "Gestures";
|
||||
public const string Navigation = "Navigation";
|
||||
|
||||
public const string ManualReview = "ManualReview";
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
|
||||
FragmentManager FragmentManager => _fragmentManager ?? (_fragmentManager = ((FormsAppCompatActivity)Context).SupportFragmentManager);
|
||||
|
||||
IPageController PageController => Element as IPageController;
|
||||
IPageController PageController => Element;
|
||||
|
||||
bool ToolbarVisible
|
||||
{
|
||||
|
@ -437,11 +437,6 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
ResetToolbar();
|
||||
}
|
||||
|
||||
void FilterPageFragment(Page page)
|
||||
{
|
||||
_fragmentStack.RemoveAll(f => ((FragmentContainer)f).Page == page);
|
||||
}
|
||||
|
||||
void HandleToolbarItemPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == MenuItem.IsEnabledProperty.PropertyName || e.PropertyName == MenuItem.TextProperty.PropertyName || e.PropertyName == MenuItem.IconProperty.PropertyName)
|
||||
|
@ -552,30 +547,50 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
_drawerToggle.DrawerIndicatorEnabled = true;
|
||||
}
|
||||
|
||||
Fragment GetPageFragment(Page page)
|
||||
{
|
||||
for (int n = 0; n < _fragmentStack.Count; n++)
|
||||
{
|
||||
if ((_fragmentStack[n] as FragmentContainer)?.Page == page)
|
||||
{
|
||||
return _fragmentStack[n];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
void RemovePage(Page page)
|
||||
{
|
||||
Fragment fragment = GetPageFragment(page);
|
||||
|
||||
if (fragment == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Go ahead and take care of the fragment bookkeeping for the page being removed
|
||||
FragmentTransaction transaction = FragmentManager.BeginTransaction();
|
||||
transaction.DisallowAddToBackStack();
|
||||
transaction.Remove(fragment);
|
||||
transaction.CommitAllowingStateLoss();
|
||||
FragmentManager.ExecutePendingTransactions();
|
||||
|
||||
// And remove the fragment from our own stack
|
||||
_fragmentStack.Remove(fragment);
|
||||
|
||||
// Now handle all the XF removal/cleanup
|
||||
IVisualElementRenderer rendererToRemove = Android.Platform.GetRenderer(page);
|
||||
|
||||
if (rendererToRemove != null)
|
||||
{
|
||||
var containerToRemove = (PageContainer)rendererToRemove.View.Parent;
|
||||
|
||||
rendererToRemove.View?.RemoveFromParent();
|
||||
|
||||
rendererToRemove?.Dispose();
|
||||
|
||||
// This causes a NullPointerException in API 25.1+ when we later call ExecutePendingTransactions();
|
||||
// We may want to remove this in the future if it is resolved in the Android SDK.
|
||||
if ((int)Build.VERSION.SdkInt < 25)
|
||||
{
|
||||
containerToRemove?.RemoveFromParent();
|
||||
containerToRemove?.Dispose();
|
||||
}
|
||||
containerToRemove?.RemoveFromParent();
|
||||
containerToRemove?.Dispose();
|
||||
}
|
||||
|
||||
// Also remove this page from the fragmentStack
|
||||
FilterPageFragment(page);
|
||||
|
||||
Device.StartTimer(TimeSpan.FromMilliseconds(10), () =>
|
||||
{
|
||||
UpdateToolbar();
|
||||
|
|
Загрузка…
Ссылка в новой задаче