0
votes

I have a page "PageA" which listens to a Changed event on a global object. The page is added in the navigation stack like this: await Navigation.PushAsync(new PageA()); The page is removed by clicking the back button in the navigation bar. When I do the same x times, I have x times PageA instances listening to the Changed event. So PageA is created over and over again, but is never really removed. How do I really get rid of the PageA when clicking the back button?

2
removing an object from the navigation stack doesn't dispose of it's instance. You can unsubscribe from the event in the OnDisappearing, or completely dispose of the reference to the page when you navigate away.Jason
@Jason, some additional questions: Is the OnDisappearing only called when the page is removed from the stack, or also when the application is put to sleep? In that case, do I have to subscribe to the event again in the OnAppearing?fantastischIdee
OnDisappearing is called when the page is removed from view. If you want to manage the subscriptions a page makes to an event, doing it in OnAppearing/OnDispappering makes sense.Jason
Do I have to worry about all the pages not being disposed? Can you give an example on how and where to dispose a page when I navigate away via the back button of the framework?fantastischIdee
This is not a xamarin question it is an object oriented programming question that boils down to does an object have anything referencing it if yes not going to get disposed if no could get disposed and most likely will. As long as page has an attached event outside of its own scope it wont get collected. You could either make sure to remove all events in ondisappearing as @Jason said or create the events within the page to have a more modular design. Better yet you can go read up on MVVM as an architectural pattern for Xamarin.Forms and other .net projects.ClintL

2 Answers

1
votes

Example of what you are doing

public partial class MyPage : ContentPage
{

    MyPage()
    {
        this.SomeEvent += SomeEventBeyondTheScopeOfThisPage();
    }

    protected override void OnDisappearing()
    {
       //You should add this
       this.SomeEvent -= SomeEventBeyondTheScopeOfThisPage();
    }
}

Which even if the page is popped from your navigation stack does not remove the reference from MyPage.SomeEvent to SomeEventBeyondTheScopeOfThisPage. So when the Garbage Collector comes along this page is going to stay and this event is going to continue to be listened for.

Just detach the event in OnDisappearing for the simple answer. You dont dispose the page you just detach all references and events outside of its scope. A better idea would be to make your code more modular and not worry about detaching the event. If the event source were coming from within the page itself it would not need to be detached.

public partial class MyPage : ContentPage
{

    MyPage()
    {
        this.SomeEvent += SomeEventWithinPagesScope();
    }

    private Task SomeEventWithinPagesScope()
    {
       //My cool event goes here           
    }
}

If it does have to be global another option would be Messaging Center. I do not believe you have to detach those listeners but I could be wrong.

https://developer.xamarin.com/guides/xamarin-forms/messaging-center/

0
votes

another reason: NavigationPage.CurrentNavigationTask.Result still refer to the popped page instance. that is why GC will not collect it. unless you navigate to other pages.