У меня возникла проблема, когда он появляется. Объекты страницы не являются мусором, собранным после того, как они были удалены. Я собрал очень простой пример этого, который демонстрирует проблему при использовании NavigationPage и метода PushAsync. На странице отображается количество страниц "Живой", используя список слабых ссылок:
public class AppNavigationPage
{
private static List<WeakReference> pageRefs = new List<WeakReference>();
public static Page GetMainPage()
{
return new NavigationPage(CreateWeakReferencedPage());
}
private static Page CreateWeakReferencedPage()
{
GC.Collect();
var result = CreatePage();
pageRefs.Add(new WeakReference(result));
// Add a second unreferenced page to prove that the problem only exists
// when pages are actually navigated to/from
pageRefs.Add(new WeakReference(CreatePage()));
GC.Collect();
return result;
}
private static Page CreatePage()
{
var page = new ContentPage();
var contents = new StackLayout();
contents.Children.Add(
new Button
{
Text = "Next Page",
Command = new Command(() => page.Navigation.PushAsync(CreateWeakReferencedPage()))
});
contents.Children.Add(
new Label
{
Text = string.Format(
"References alive at time of creation: {0}",
pageRefs.Count(p => p.IsAlive)),
HorizontalOptions = LayoutOptions.CenterAndExpand
});
page.Content = contents;
return page;
}
}
При нажатии кнопки "Следующая страница" создается новая страница с меткой с фиксированным значением, показывающей количество ссылок на страницы в момент, когда эта страница была создана. Каждый раз, когда вы нажимаете кнопку, вы, очевидно, видите, что это число увеличивается на 1. Мое понимание заключается в том, что когда вы нажимаете "назад" на странице навигации, представление должно быть выскользнуто из стека и выброшено (это будет GC'd), Однако, когда я запускаю этот тестовый код, он указывает, что после того, как мы вернемся, это представление сохраняется в памяти. Это можно продемонстрировать, нажав "Следующая страница" несколько раз, пока счетчик ссылок не будет равен 3. Если вы затем щелкните "Назад" и затем "Следующая страница" , я считаю, что счетчик ссылок должен быть равен 3 (это означает, что старая страница была GC'd до новой один был создан), однако новый счетчик ссылок теперь равен 4.
Это кажется довольно серьезной ошибкой в реализации X-форме навигации для прошивки (я не проверял это для других платформ), мое предположение того, что какое-то образом связанно с сильной проблемой Reference цикла, описанной здесь: http://developer.xamarin.com/guides/cross-platform/application_fundamentals/memory_perf_best_practices/
Кто-нибудь еще столкнулся с этим и/или придумал решение/обходное решение для него? Кто-нибудь еще согласится, что это ошибка?
В качестве дополнения я сделал второй пример, который не включает в себя NavigationPage (поэтому вместо этого нужно использовать PushModalAsync), и обнаружил, что у меня такая же проблема, поэтому эта проблема не выглядит уникальной для навигации NavigationPage. Для справки код для этого (очень похожего) теста находится здесь:
public class AppModal
{
private static List<WeakReference> pageRefs = new List<WeakReference>();
public static Page GetMainPage()
{
return CreateWeakReferencedPage();
}
private static Page CreateWeakReferencedPage()
{
GC.Collect();
var result = CreatePage();
pageRefs.Add(new WeakReference(result));
// Add a second unreferenced page to prove that the problem only exists
// when pages are actually navigated to/from
pageRefs.Add(new WeakReference(CreatePage()));
GC.Collect();
return result;
}
private static Page CreatePage()
{
var page = new ContentPage();
var contents = new StackLayout();
contents.Children.Add(
new Button
{
Text = "Next Page",
Command = new Command(() => page.Navigation.PushModalAsync(CreateWeakReferencedPage()))
});
contents.Children.Add(
new Button
{
Text = "Close",
Command = new Command(() => page.Navigation.PopModalAsync())
});
contents.Children.Add(
new Label
{
Text = string.Format(
"References alive at time of creation: {0}",
pageRefs.Count(p => p.IsAlive)),
HorizontalOptions = LayoutOptions.CenterAndExpand
});
page.Content = contents;
return page;
}
}