Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Application.Current.MainPage vs Navigation.PushAsync() vs Navigation.PushModalAsync()

I'm developing an Xamarin Forms App (PCL) that does NOT need a back button. That app has three pages : a SplashScreenPage to load data, a LoginPage if the user needs to login and a RootPage which is a MasterDetailPage. I was wondering what was the best option to navigate between pages (to avoid memory leaks for example):

First solution:

Application.Current.MainPage = new ContentPage();

Second solution:

Navigation.PushAsync(new NavigationPage(new ContentPage()));

then

NavigationPage.SetHasNavigationBar(this, false);
ClearNavigationStack();

Third solution

await Navigation.PushModalAsync(new NavigationPage(new ContentPage()));

then

NavigationPage.SetHasNavigationBar(this, false);
ClearModalStack();
like image 479
Nicolas Bodin-Ripert Avatar asked Jan 04 '23 06:01

Nicolas Bodin-Ripert


2 Answers

As describe by @will-decter none of the above solutions could cause memory leaks if implemented correctly.

You can use any of the above solutions. And generally you need not to do anything to clear previous page. Garbage Collector automatically do that for you (Not immediately but after some time based on some condition). Consider first solution:

Application.Current.MainPage = new Page1();

Now if you assign new page like this.

Application.Current.MainPage = new Page2();

As Page1 is no longer in use, GC will collect Page1 object after some time when GC try to reclaim some memory. You can also use GC.Collect() to force GC to reclaim memory immediately but as GC.Collect() operation is expensive so I would suggest you should not call it from your code rather optimize your code so don't need to call it.

But if your page is subscribe to an event and does not unsubscribe it then in that case GC cannot collect that the page even if you call GC.Collect() method. So make sure that you unsubscribe any subscribed event like this:

public class MainPage : ContentPage
{
     protected override void OnAppearing()
     {
         base.OnAppearing();
         MyEntry.TextChanged += MyEntry_TextChanged;
     }

     protected override void OnDisappearing()
     {
         base.OnDisappearing();
         MyEntry.TextChanged -= MyEntry_TextChanged;
     }
}

(You can skip unsubscibe if event was subscribe from xaml as in that case Xamarin Form uses WeakReference)

This will ensure MainPage is collected by GC when needed.

I would suggest to read this article to get better insight how GC works in Xamarin and how can you increase your application performance.

https://developer.xamarin.com/guides/cross-platform/deployment,_testing,_and_metrics/memory_perf_best_practices/

like image 74
Pranshu Aggarwal Avatar answered Jan 05 '23 20:01

Pranshu Aggarwal


think best option to navigate between pages is

in App.cs

public App()
{
    var nav = new NavigationPage(new Login());
    MainPage = nav;
}

then on Login success click:

void OnLoginClicked(object sender, EventArgs e)
{
    Application.Current.MainPage = new NavigationPage(new MasterPage());
}

Not need to add "NavigationPage.SetHasNavigationBar(this, false);"

like image 42
Pratik Avatar answered Jan 05 '23 21:01

Pratik