How to restore the navigation stack after page suspend / resume in Xamarin.Forms

codenutzcodenutz GBMember

Hey Guys,

I'm just getting used to Xamarin.Forms and cant seem to find a standard way of restoring the navigation stack after a suspend / restore (like when the device gets rotated).

Using either the v1.3.0 release or maybe even xamarin.forms.labs I can capture some restore/suspend events, but I dont understand how I'm meant to restore the navigation stack in my app?

For example, if I have my HomeView and HomeViewModel, which has a list view of items. Somebody clicks the list view item and it navigates to my ItemView and ItemViewModel. Then the user rotates the screen - how do I restore them to where they just were?

Can anyone point me in the right direction?

Thanks

Matt

Posts

  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    I don't think you're supposed to need to do anything. Is something not working?

  • codenutzcodenutz GBMember

    When I rotate the screen (or hit any suspend / restore cycle) the whole Xamarin.Forms app just goes back to the MainScreen.

  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    I don't think that's expected behavior.

  • codenutzcodenutz GBMember

    I think it must be given the way that Xamarin.Forms is initialized. For example, in an android app the whole Xamarin.Forms app is created as part of the MainActivity OnCreate method (which gets hit during every resume cycle).

    Therefore the entire Xamarin.Forms app gets recreated every time the app is paused / resumed.

  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    I guess you're right. I'm too much of an idealist. I thought "how could they release an API that doesn't handle that because no one could get anything done with it", but sure enough it looks like they did. That's very disappointing. Here is an older forum post I found discussing the same thing:

    http://forums.xamarin.com/discussion/21400/forms-app-loses-all-state-and-boots-from-scratch-when-switching-between-apps

    There a uservoice link at the bottom so you can go vote for the idea to fix it.

  • codenutzcodenutz GBMember

    Voted!! Thanks for the link!

    I'm with you - it seems pretty fundamental to me and I am surprised that its just 'the way it is'

  • LudovicThomasLudovicThomas ✭✭ USMember ✭✭

    +1 uservoice. Any feedback on that one Xamarin team?

  • chris_riesgochris_riesgo ✭✭✭ USUniversity ✭✭✭

    Make sure you guys actually vote on user voice. No one monitors "+1" comments in these forums.

  • codenutzcodenutz GBMember

    I gave it a +3 on user voice

  • LudovicThomasLudovicThomas ✭✭ USMember ✭✭

    +1 uservoice means I voted +1 on uservoice :) Thanks chris_riego

  • CraigDunnCraigDunn Xamurai USXamarin Team Xamurai
    edited October 2014

    @mattwhetton‌ does your Android app have the config changes set correctly

    [Activity (Label = "Todo", 
        MainLauncher = true, 
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    

    ? this isn't a panacea but should be the minimum to avoid apps 're-starting' on rotation in Android

    To clarify Chris' point... "+x" postings in the forum just make the thread longer and harder to read. UserVoice votes matter, on the forum useful content is what is important.

    And finally, yes, we're working on it!

  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    FWIW, Google doesn't recommend using that option.

  • CraigDunnCraigDunn Xamurai USXamarin Team Xamurai

    categorically, or in certain circumstances (like when their layout engine is managing the controls rather than ours?)

    got a link?

  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    See the note here for instance: http://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange

    Note: Handling the configuration change yourself can make it much more difficult to use alternative resources, because the system does not automatically apply them for you. This technique should be considered a last resort when you must avoid restarts due to a configuration change and is not recommended for most applications.

    I believe their current recommendation is to use Fragments that retain their instances. Our application used very lightweight (practically empty) activities which just used a single fragment where we kept all of the real logic. The views are still recreated when rotating, but the fragment itself can be reused and maintain its state in the process. The activity is also thrown away and recreated, but it ends up with the same fragment instance so we don't care.

  • CraigDunnCraigDunn Xamurai USXamarin Team Xamurai

    That 'official' page also says

    Remember: When you declare your activity to handle a configuration change, you are responsible for resetting any elements for which you provide alternatives. If you declare your activity to handle the orientation change and have images that should change between landscape and portrait, you must re-assign each resource to each element

    ... so yeah they are very concerned about developers mucking up their system of alternate layouts and drawables (-landscape, etc) which is fair enough. Xamarin.Forms is managing that stuff, we're "handling the configuration change"... notice that all the layouts (that support it) resize/stretch/fit the new orientation.

    I'm not saying it's perfect, but that's the disconnect between their advice and how Xamarin.Forms currently works. We know there's room for improvement here... see new Sleep/Resume/Start events features in 1.3 as a starting point along that road.

  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    But they're also concerned about not handling configuration changes other than "orientation". You might get by with this approach until someone does something like connects a hardware keyboard while your app is running, in which case suddenly your app loses all state again (because that's a configuration change too). You could throw in every single configuration option so that it never gets thrown out, but then it's much harder to say for sure that you're handling everything you should be handling in response to each one of those configuration changes. Orientation is the easy one, but what about all the others?

    Personally I think this design (Google's) wasn't well thought out. Their approach is to throw everything out and rebuild it (very tediously) when any "configuration" state changes, and their definition of "configuration" is extremely broad. I think they recognize that this approach isn't practical, and their latest recommendation to use Fragments kind of hacks around the old architecture in away that at least preserves your state (if not your views).

  • CraigDunnCraigDunn Xamurai USXamarin Team Xamurai

    Indeed. Note that we only recommend handling the orientation and screensize changes; there are 13 Android.Content.PM.ConfigChanges specified (so far) so for the rest (eg. Keyboard, Locale) your Xamarin.Forms app is still re-starting... so yes, there's more work to do be done at this end!

  • StefanoChiariStefanoChiari IEMember

    I have the same problem, any news how to avoid Android restarting the activity or how to restore last navigation page ?
    I have this problem when taking a picture from the camera, it goes back to the initial app page and not to the page from where I wanted to take and display a photo.

  • batmacibatmaci ✭✭✭✭✭ DEMember ✭✭✭✭✭
    > @StefanoChiari said:
    > I have the same problem, any news how to avoid Android restarting the activity or how to restore last navigation page ?
    > I have this problem when taking a picture from the camera, it goes back to the initial app page and not to the page from where I wanted to take and display a photo.

    Wow did you find any good solution for this?
  • StefanoChiariStefanoChiari IEMember

    @batmaci : I have disabled on Android developer options the option "Don't keep activities" : this setting destroys any activity as soon as the user leaves it. When you take a picture you leave the application opening the camera, then your app activity is distroyed and when you try to come back after taking the picture it goes to the main view cause your app has been reset.

  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    Disabling the developer option doesn't fix the bug. Any time you move from one activity to another Android may throw the original activity out of memory. When the second activity finishes then the framework will recreate the original activity. That is where state can get lost, including (in Forms) the navigation stack.

    The Android developer option is merely a debugging tool that forces this to happen every time instead of only occasionally (based on memory pressure). It's a tool to test that you handle this correctly. Disabling the option only means you're not testing whether your app handles this (ignoring the problem).

    There is no solution to this problem in Xamarin.Forms. It was tracked by this bug, but that was closed and replaced with a feature request, and I'm not sure whether that is visible to us.

  • batmacibatmaci ✭✭✭✭✭ DEMember ✭✭✭✭✭
    In mean time is there any workaround? I heard people saying store the state of your app but what is an app state? I can store the Last navigated page but how to store navigation stack
  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    There is no easy workaround. iOS has a complex API for saving and restoring app state (see here), and you would basically have to build something similar for Android. It would have to be able to detect when the activity is being destroyed, visit each page in the navigation stacks (remember, there is both a modal and a non-modal stack, so you really have a tree), record the type of the page, and then ask the page to serialize its state. There is an existing Android API for serializing state on activity destruction (OnSaveInstanceState) so you would save it there. Then when the activity is recreated (OnRestoreInstanceState) you would have to deserialize that state, recreate each page, and then rebuild the navigation stack.

    Yes, this is really complicated. I mostly blame Android for having such a ridiculous system in the first place, but Xamarin also should share some blame because in most cases using a retained fragment would have been sufficient. That work would have to be done by them, though. It would still not be sufficient for cases where the entire application is killed and relaunched (i.e., the whole process goes away).

  • I believe with the latest Xamarin Forms it can handle the config changes i.e. rotation etc. There is a ConfigurationChanges attribute that needs to be decorated in the MainActivity.cs.

    [Activity(Label = "Roamer",
            Icon = "@drawable/icon",
            Theme = "@style/splashscreen",
            MainLauncher = true,
            ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden,
            ScreenOrientation = ScreenOrientation.Portrait)]
    

    In my case, it was giving me a lot of grief because I was connecting a bluetooth barcode scanner and it was causing a config change and my app was getting reset and the navigation stack went back to the root. Hope this helps somebody who is in the same situation as I was and stops them wasting hours.

  • DaronRiceDaronRice ✭✭ USMember ✭✭

    I am having the same exact problem.... ConfigChanges.ScreenSize | ConfigChanges.Orientation will save the page you are on when the screen is rotated, but will not save your android menu. Removing those flags will reload your android menu, but will not save the page you are on when rotated. Supposely, you can use OnConfigurationChanged() to reload the menu, but i haven't been able to get it working. I am only using an android menu to put the searchview in the toolbar. Any suggestion from anyone here on how to handle that?

  • JoeSchmeltzerJoeSchmeltzer ✭✭ USMember ✭✭

    @KamalpreetChauhan, is there a way I can tell what is causing my app to cycle? I'm hoping it's one of those things and I can simply add that config type to ConfigurationChanges as you suggest, but I'm not sure what is causing my app to restart. When I'm in OnPause, OnStop, or OnDestroy, is there a way to see what caused it? Thanks.

  • JoeSchmeltzerJoeSchmeltzer ✭✭ USMember ✭✭

    As usual, I figured this out right after asking. For anyone else with this problem: in OnPause or OnDestroy, you can check IsChangingConfigurations for the list of configuration(s) that caused the restart. In fact, IsChangingConfigurations.ToString() gives a nice comma-delimeted list for logging. I hope this helps someone else not have to spend days on this!

Sign In or Register to comment.