App with a TabbedPage navigation with 5 tabs.
The last one is "Settings".
I have a switch on that tab which, when enabled, asks for permissions to access the address book.
On Android, OnDisappearing is fired from that tab when the system displays the dialog box requesting the user to accept (or deny) it.
And OnAppearing is fired when this system dialog is dismissed.
On iOS, those supplemental events are not fired.
As in iOS, those events should not fire on Android.
On Android, they do and we must take specific measure not to initialize the tab again because we are reentering in OnAppearing when dismissing the system dialog box.
Tested on Android simulator.
Could you please upload a reproduction solution which shows the described behavior to aid further investigation?
I lack time... but I'll try.
Decided to do it now otherwise might not happen.
There you go.
I modified the TabbedPageWithNavigationPage sampled found here : https://developer.xamarin.com/samples/xamarin-forms/Navigation/TabbedPageWithNavigationPage/
Build it, run it, go to tab settings, click on button.
On Android, when clicking the button, the system dialog appears and the OnDisappearing is fired.
Dismiss the dialog and OnAppearing is fired.
On iOS, no extra events fired, as expected.
TabbedPageWithNavigationPage_modified.zip
When you request a permission on Android, the Activity is paused when the dialog is presented and resumed when the dialog is closed. I don't think it would be wise, if it's even possible, to not forward those system events to Forms when you make permission requests.
But then, as it is now, the Xamarin Forms behavior is not consistent between iOS & Android.
Which do you think is more important to your users, that your app's behavior is consistent between their Android phone and someone else's iPhone, or that your app is consistent with all of the other apps on their phone?
Besides, it takes as little as 3 lines of code to prevent re-initialization in OnAppearing().
Ouch.
Ok then.
I was only reporting my findings here because I had to find it the hard way as I haven't seen this documented anywhere.
And because I'd thought that the spirit of XF were to make things consistent between platform.
Nevermind.
Reopening this, only to wait for an official position from an XF Team "Member".
They initially asked me for a repro, which I did.
So I suppose they were interested in digging further.
And if the solution is provided by some improved documentation rather than code or behavior change, so be it, it is fine by me.
At least, one will be able to search for this github issue.
And because I'd thought that the spirit of XF were to make things consistent between platform.
I feel like the interpretation of whether this is consistent or not is relative. To make this specific example act "consistent" with those events we'd have to know the intent of why Android is disappearing the fragment and then make a judgement call whether to fire OnDisappearing which seems dangerous.
I feel like the way the behavior is now is consistent because OnDisappearing is representing the lifecycle of the platform correctly.
OnDisappearing doesn't really signify a single intent (going back a page, going forward a page, minimizing the app, this scenario, or probably some additional cases I can't think of) so my recommendation would be to take whatever logic you have in OnDisappearing that you don't want firing and tie it to something that represents specifically when you are wanting that code to fire.
I'm guessing for this case you are wanting to know when a page is navigated away from via tabs? So for that would it work to do what you need to do via the TabbedPage? So in the tabbedpage when the selectedtab changes then propagate that out where you need to?
I feel like the interpretation of whether this is consistent or not is relative.
True
I feel like the way the behavior is now is consistent because OnDisappearing is representing the lifecycle of the platform correctly.
I do agree with that too.
For the rest, I've managed - very easily indeed - to circumvent this specific behavior.
No problem with that.
The issue can be closed if there is nothing to add to it.
Again, this issue will stay and be searchable so that alone should be enough for now.
Soooo...
@nbsoftware
HOW did you work around this? :)
I can't recall exactly, it's been a year now...
On Android, something like set a boolean just before requesting the permissions and ignoring the OnDisappearing if that boolean is set. And of course, reseting that boolean when system dialog has been dismissed.
Not very pretty but it worked at the time.
1) This is a total showstopper, as your app will go into an infinite loop when any initialisation is done in OnAppearing/cleanup in OnDisappearing.
2) This is inconsistent because the Application's OnSleep and OnResume events are not triggered when this happens. (Bonus question: why are there no OnSleep and OnResume events in Application that other UIs could subscribe to? You can't really make self-contained UI libraries without them).
3) Because this OnAppearing is indistinguishable from a normal navigation event there's not much you can do.
The flow is to ask for permissions in OnAppearing. I tried to add a flag in OnSleep/OnResume but as they are not called I can't really do anything (I was hoping they'd get called in such an order I could detect whether OnAppearing/OnDisappearing were called due to a sleep event). Because the permission dialog's focus calls OnDisappearing/OnAppearing, it goes into an infinite loop. It is somehow manageable with incredible code smell and flags if everything is confined to one page, but real apps are not.
It's great that the devs think this is consistent. It's horrible to use though! 👍
Most helpful comment
True
I do agree with that too.
For the rest, I've managed - very easily indeed - to circumvent this specific behavior.
No problem with that.
The issue can be closed if there is nothing to add to it.
Again, this issue will stay and be searchable so that alone should be enough for now.