As a step in the direction of getting https://github.com/xamarin/Xamarin.Forms/issues/2210 resolved we should first fix OnAppearing/OnDisappearing so that they fire consistently across platform and that we resolve the cases where OnAppearing/OnDisappearing fires at odd times.
Existing Issues
https://github.com/xamarin/Xamarin.Forms/issues/2240
https://github.com/xamarin/Xamarin.Forms/issues/2716
https://github.com/xamarin/Xamarin.Forms/issues/5418
https://github.com/xamarin/Xamarin.Forms/issues/4986
https://github.com/xamarin/Xamarin.Forms/issues/4608
Example or Ordering Issue
Currently, where MainPage is a TabbedPage you get this:
iOS:
MainPage.CurrentPageChanged event handled
SchedulePage.OnDisappearing() called
SettingsPage.OnAppearing() called
Android:
SchedulePage.OnDisappearing() called
SettingsPage.OnAppearing() called
MainPage.CurrentPageChanged event handled
The issue with the current OnAppearing implementation is that it's a hodge podge of platform hooks and in some cases cross platform. For example currently on iOS OnAppearing fires when ViewDidAppear is called which is OnAppeared not OnAppearing which is inconsistent with Android.
Cases like this on Android TabbedPageRenderer don't make sense
C#
Element.CurrentPage = Element.Children[position];
Element.CurrentPage.SendAppearing();
SendAppearing here should just fire from the Element not from the Renderer that way it's cross platform and consistent.
flag for EnableNewLifeCycleEvents that can become default in 5.0.0 => that's sound good!
We really need this bug fixed for we're having the same issue with a certain page's on appearing method executing even if it's never the active tab
Could this be related? I have a System.NullReferenceException in a method that doesn't really have anything in it that could be causing a NullReferenceException.
CardsTabViewModel.OnDisappearing ()
System.NullReferenceException: Object reference not set to an instance of an object
Android: 7.0
Android Build: NRD90M
Manufacturer: vivo
Model: vivo 1714
CrashReporter Key: fa46abc2-3677-4ef2-bc43-6f7f13391218
Start Date: 2019-12-26T08:10:50.939Z
Date: 2019-12-26T08:12:43.897Z
Xamarin Exception Stack:
System.NullReferenceException: Object reference not set to an instance of an object
at Japanese.CardsTabViewModel.OnDisappearing () [0x00018] in <460a5aefe005480680b03f394d540b43>:0
at Japanese.CardsTabPage.OnDisappearing () [0x00006] in <460a5aefe005480680b03f394d540b43>:0
at Xamarin.Forms.Page.SendDisappearing () [0x00040] in
at Xamarin.Forms.ShellContent.SendDisappearing () [0x0001f] in
at Xamarin.Forms.ShellSection.PresentedPageDisappearing () [0x0000f] in
at Xamarin.Forms.ShellSection.SendDisappearing () [0x00006] in
at Xamarin.Forms.ShellItem.OnCurrentItemChanged (Xamarin.Forms.BindableObject bindable, System.Object oldValue, System.Object newValue) [0x0000a] in
at Xamarin.Forms.BindableObject.SetValueActual (Xamarin.Forms.BindableProperty property, Xamarin.Forms.BindableObject+BindablePropertyContext context, System.Object value, System.Boolean currentlyApplying, Xamarin.Forms.Internals.SetValueFlags attributes, System.Boolean silent) [0x0012a] in
at Xamarin.Forms.BindableObject.SetValueCore (Xamarin.Forms.BindableProperty property, System.Object value, Xamarin.Forms.Internals.SetValueFlags attributes, Xamarin.Forms.BindableObject+SetValuePrivateFlags privateAttributes) [0x00173] in
at Xamarin.Forms.BindableObject.SetValueCore (Xamarin.Forms.BindableProperty property, System.Object value, Xamarin.Forms.Internals.SetValueFlags attributes) [0x00000] in
at Xamarin.Forms.Element.SetValueFromRenderer (Xamarin.Forms.BindableProperty property, System.Object value) [0x00000] in
at Xamarin.Forms.ShellItem.Xamarin.Forms.IShellItemController.ProposeSection (Xamarin.Forms.ShellSection shellSection, System.Boolean setValue) [0x0002d] in
at Xamarin.Forms.Platform.Android.ShellItemRenderer.ChangeSection (Xamarin.Forms.ShellSection shellSection) [0x00006] in <8e6bfbbc42c1411bbf372065ebc4eeb9>:0
at Xamarin.Forms.Platform.Android.ShellItemRenderer.OnItemSelected (Android.Views.IMenuItem item) [0x0006d] in <8e6bfbbc42c1411bbf372065ebc4eeb9>:0
at Xamarin.Forms.Platform.Android.ShellItemRenderer.Android.Support.Design.Widget.BottomNavigationView.IOnNavigationItemSelectedListener.OnNavigationItemSelected (Android.Views.IMenuItem item) [0x00000] in <8e6bfbbc42c1411bbf372065ebc4eeb9>:0
at Android.Support.Design.Widget.BottomNavigationView+IOnNavigationItemSelectedListenerInvoker.n_OnNavigationItemSelected_Landroid_view_MenuItem_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_item) [0x0000f] in <4f5f76e121b14fe1a273d1142e810c70>:0
at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.55(intptr,intptr,intptr)
Thread 17677:
0 java.lang.Object.wait(Object.java:-2)
1 java.lang.Daemons$ReferenceQueueDaemon.run(Daemons.java:153)
2 java.lang.Thread.run(Thread.java:761)
Thread 17678:
0 java.lang.Object.wait(Object.java:-2)
1 java.lang.Object.wait(Object.java:407)
2 java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:188)
3 java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:209)
4 java.lang.Daemons$FinalizerDaemon.run(Daemons.java:208)
5 java.lang.Thread.run(Thread.java:761)
Thread 17679:
0 java.lang.Thread.sleep(Thread.java:-2)
1 java.lang.Thread.sleep(Thread.java:371)
2 java.lang.Thread.sleep(Thread.java:313)
3 java.lang.Daemons$FinalizerWatchdogDaemon.sleepFor(Daemons.java:331)
4 java.lang.Daemons$FinalizerWatchdogDaemon.waitForFinalization(Daemons.java:373)
5 java.lang.Daemons$FinalizerWatchdogDaemon.run(Daemons.java:257)
6 java.lang.Thread.run(Thread.java:761)
Thread 17680:
0 dalvik.system.VMRuntime.runHeapTasks(VMRuntime.java:-2)
1 java.lang.Daemons$HeapTaskDaemon.run(Daemons.java:476)
2 java.lang.Thread.run(Thread.java:761)
Thread 17691:
0 android.os.MessageQueue.nativePollOnce(MessageQueue.java:-2)
1 android.os.MessageQueue.next(MessageQueue.java:328)
2 android.os.Looper.loop(Looper.java:148)
3 android.os.HandlerThread.run(HandlerThread.java:61)
Thread 17693:
0 java.lang.Object.wait(Object.java:-2)
1 java.lang.Thread.parkFor$(Thread.java:2127)
2 sun.misc.Unsafe.park(Unsafe.java:325)
3 java.util.concurrent.locks.LockSupport.park(LockSupport.java:161)
4 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2035)
5 java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:413)
6 java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1058)
7 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1118)
8 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
9 java.lang.Thread.run(Thread.java:761)
Thread 17694:
0 android.os.MessageQueue.nativePollOnce(MessageQueue.java:-2)
1 android.os.MessageQueue.next(MessageQueue.java:328)
2 android.os.Looper.loop(Looper.java:148)
3 android.os.HandlerThread.run(HandlerThread.java:61)
@rscholey I don't think your problem has anything in common. You should debug it to see where exactly the NRE occurs. Also have a look on your XAML code.
It looks like this is still happening. We simply open a modal page Shell.Current.Navigation.PushModalAsync() and then dismiss it using Navigation.PopModalAsync(); Neither OnAppearing nor OnDisappearing event is called on Android.
Also, under some conditions these events get called multiple times.
Are there any suggested work arounds? Can someone point to a pattern how to design/architect the UI without reliable life cycle events such as Appearing and Disappearing?
@dmitrymal a workaround for me is to use an event or an observable that fires in a service when the page is closed. This event or observable then triggers the OnAppearing on Android.
Run also into the OnAppearing difference between iOS and Android. iOS is much tool late fired. Please fix it.
Also running into this. This issue is almost a year old and it's still not fixed. disappointing
This issue is really annoying, indeed. Can you provide more info on why this hasn't been merged yet? Is it a design decision?
Just jumped into this issue, really annoying indeed.
Same here.
Most helpful comment
@dmitrymal a workaround for me is to use an event or an observable that fires in a service when the page is closed. This event or observable then triggers the OnAppearing on Android.