Bug 44159 - MasterDetail not releasing Page - Forms Android
Summary: MasterDetail not releasing Page - Forms Android
Status: RESOLVED FIXED
Alias: None
Product: Forms
Classification: Xamarin
Component: Forms ()
Version: 2.3.2
Hardware: PC Mac OS
: Normal major
Target Milestone: ---
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2016-09-09 21:19 UTC by Andrew
Modified: 2016-12-09 00:03 UTC (History)
6 users (show)

Tags: ac Android
Is this bug a regression?: ---
Last known good build:


Attachments
Sample (974.33 KB, application/zip)
2016-09-09 21:19 UTC, Andrew
Details
sample #2 (968.27 KB, application/zip)
2016-09-11 19:20 UTC, Andrew
Details
New Sample (49.28 KB, application/zip)
2016-10-17 13:56 UTC, Andrew
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description Andrew 2016-09-09 21:19:04 UTC
Created attachment 17402 [details]
Sample

Sample provided. 

Summary:  When you navigate off the MasterDetail, the previous page viewed is kept in memory.  The code will execute on the previous page if the app is minimized (background) and then restored (foreground).  The NavigationStack shows the page removed before minimizing it, but when restored the page exist on the NavigationStack causing code to execute on a page that is not visible.  

I have reproduced this memory leak in several sample projects.

The problem:  serious problem.  Code executes on the previous ContentPage after Xamarin.Forms.Application.MainPage has been changed.  The page is not visible.  should be disposed.  code runs and the app crashes.

To reproduce

run the sample application on android (device or android player)
click the Master menu item "Blogs"
click on one of the listview items.
  this code will run:
      listView.ItemTapped += (sender, args) =>
      {
         Xamarin.Forms.Application.Current.MainPage = new NavigationPage(new LogoutPage());
      };
            
The mainPage has changed.  The navigation stack only shows the LogoutPage.
Minimize the application on android.  leave it in the background. select another app on the device (any)
Go back to the sample application.
The "override void OnAppearing()" on the Blog Page will fire. (this page has been removed from the NavigationStack and should not exist). No code should fire on this page "Blog"

The problem is:
The MainPage has changed.  There is no reference to the “Blog" Page, but after the application is returned from the background it runs on a disposed page and causes errors running code on a page that should have been removed!

How it should work:
After this line:
Xamarin.Forms.Application.Current.MainPage = new NavigationPage(new LogoutPage());

the Blog page should be removed. The onAppearing() should not FIRE for a page that is not APPEARING.  The page should be disposed.
Comment 1 Andrew 2016-09-11 19:20:22 UTC
Here a better sample.

Run Sample.
Click on listview item
Should see logout page

minimize the app (set to background)
switch to another app.
restore app.

should get Alert on the Blog page that has been removed.  (The sample is executing code on a removed page from the stack).
Comment 2 Andrew 2016-09-11 19:20:53 UTC
Created attachment 17411 [details]
sample #2

new sample
Comment 3 Andrew 2016-09-12 14:15:38 UTC
Here my hack I wrote to work around this issue.  The commented code failed.  Should not have to spend processing time or write hacks like this to prevent code from running on pages that should have been removed from the NavigationStack.

		/// <summary>
		/// to check for the bug when the CurrentPage is removed from the stack but keeps on firing
		/// </summary>
		/// <returns><c>true</c>, if exists on stack was paged, <c>false</c> otherwise.</returns>
		private bool PageExistsOnStack()
		{
			if (Device.OS == TargetPlatform.Android)
			{
				// do not like it.  evil code below. 
				var nav = AppManager.Nav;
				if (nav == null || nav.Nav == null) return false;

				// hack for first page load
				if (nav.Nav.NavigationStack.Count == 0) return true;

				var exists = nav.Nav.NavigationStack.Where(x => x.GetType().Name == PageTypeName).FirstOrDefault();
				if (exists == null)
				{
					var temp = nav.Nav.NavigationStack.Where(x => x is TabbedPage);
					if (temp != null && temp.Count() > 0)
					{
						foreach (var item in temp)
						{
							var t = (TabbedPage)item;
							exists = t.Children.Where(x => x.GetType().Name == PageTypeName).FirstOrDefault();
							if (exists != null) break;
						}
					}
				}
				if (exists == null && nav.Nav.ModalStack != null)
				{
					exists = nav.Nav.ModalStack.Where(x => x.GetType().Name == PageTypeName).FirstOrDefault();
				}

				//var exists = Navigation.NavigationStack.Where(x => x.GetType().Name == PageTypeName).FirstOrDefault();
				//if (exists == null)
				//{
				//	var temp = Navigation.NavigationStack.Where(x => x is TabbedPage);
				//	if (temp != null && temp.Count() > 0)
				//	{
				//		foreach (var item in temp)
				//		{
				//			var t = (TabbedPage)item;
				//			exists = t.Children.Where(x => x.GetType().Name == PageTypeName).FirstOrDefault();
				//			if (exists != null) break;
				//		}
				//	}
				//}
				//if (exists == null && Navigation.ModalStack != null)
				//{
				//	exists = Navigation.ModalStack.Where(x => x.GetType().Name == PageTypeName).FirstOrDefault();
				//}
				return exists != null;
			}
			return true;
		}
Comment 4 E.Z. Hart [MSFT] 2016-10-14 23:22:12 UTC
Andrew,

I'm trying to reproduce the issue you're describing, but when I resume your repro project I simply see the Logout page that was displaying when I suspended the application. The Blog page does not display, nor does the alert display.

I *can* reproduce the issue if I go to "Settings" on my device, open "Developer options", and under "Apps"' turn on "Don't keep activities". This causes the application to be destroyed as soon as I leave it; "resuming" it after that is effectively re-launching it from scratch, which causes the Blog page to display, along with the alert. Could that be what you're seeing?
Comment 5 Andrew 2016-10-17 13:55:55 UTC
New Sample posted.

Click Logout button
Navigation Stack is cleared with setting MainPage. 

get app to background.  restore app to foreground.

An Alert appears on a disposed page that does not exist on the Navigation Stack.  ItemPage.cs was removed when I set:

Xamarin.Forms.Application.Current.MainPage = new NavigationPage(new LogoutPage());

will add a screencast after I convert the flash video.
Comment 6 Andrew 2016-10-17 13:56:35 UTC
Created attachment 18074 [details]
New Sample
Comment 7 Andrew 2016-10-17 14:06:40 UTC
I turned off developer options on my device to test if the "Settings" was the problem.  The alert still appears on the LogoutPage.  I can not imagine this is my design to have code running on the "ItemPage" after it been removed from the NavigationStack.
Comment 8 Andrew 2016-10-17 14:17:17 UTC
http://www.screencast.com/t/Dp3RYIBn87
Comment 9 E.Z. Hart [MSFT] 2016-10-17 21:54:02 UTC
Confirmed up through 2.3.3.163-pre3
Comment 10 adrianknight89 2016-12-08 04:44:15 UTC
I ran your "New Sample". If you hit the back button, then the activity is destroyed. When you foreground the app, the activity is re-created so you end up with the original page.
Comment 11 Andrew 2016-12-08 20:08:45 UTC
This bug existed through 2.3.3.16-pre3 as confirmed by E.Z Hart.  

I tested it with: 2.3.4.171-pre1 and it is fixed.  I am closing the bug as I am not experiencing the behavior in 2.3.4.171-pre1.  

"New Sample" works as expected in 2.3.4.171-pre1.