Windows Phone Silverlight Application Life Cycle for Application Launch, Activate, and Deactivate Events


Download 109.73 Kb.
NameWindows Phone Silverlight Application Life Cycle for Application Launch, Activate, and Deactivate Events
A typeDocumentation




c:\users\a-ronloi.redmond\pictures\wp7 logos\wp_brd_yel_h_rgb.png

Windows Phone Silverlight Application Life Cycle for Application Launch, Activate, and Deactivate Events

Marketplace

Anti-Piracy Model

Microsoft Corporation

November 2010

Version 1.0

Applies To: Windows® Phone 7

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the companies, organizations, products, domain names, e-mail addresses, logos, people, places, and events depicted in examples herein are fictitious. No association with any real company, organization, product, domain name, e-mail address, logo, person, place, or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation.

Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.

© 2010 Microsoft Corporation. All rights reserved.

Microsoft MSDN, Silverlight, Windows, and Windows Phone are trademarks of the Microsoft group of companies.

All other trademarks are property of their respective owners.


Table of Contents




Introduction

When you write a Silverlight Windows Phone application, a full understanding of the sequence of events that occur in your application for common user scenarios is critical to writing a robust and responsive application. The focus of this topic will be on the flow of events that occur, and what actions the developer should perform in each event.

For an overview of the Windows Phone Execution model, please see the following MSDN topic. We will assume that you have familiarity with the topics discussed there.

The complete source code for the Unit Converter can be found in a starter kit which may be downloaded here.

Application Event Flow

There are four main scenarios that we will review. The emphasis will be on the application and page methods and events that that will be executed during application startup. The flow of execution is shown for:

  • Application launch.

    • The user has started the application by pressing the application icon.

  • Application activation after the application has been tombstoned.

    • The user has left the application by pressing the Start button, and returned to the application by pressing the Back button.

  • Application activation when the application was not tombstoned.

    • The user has pressed the Start and Back buttons in quick succession, so objects are still in memory.

  • Application deactivation.

    • The user has switched to another application either by pressing the Start button or the Back button.


Note: For the PageLayoutUpdated event to be called, a page must subscribe to this event.

Notice that the sequence of events between an application that is launched from scratch and an application that is activated after it has been previously tombstoned, are identical. The only difference is in the application logic around how an application that is launched from scratch has to be fully initialized instead of being restored from the tombstoned state, as is the case for an application that is activated from the tombstoned state.

However, for the case of an application that was activated, but not tombstoned, we see a substantially smaller number of methods/events processed. Because all application objects are still in memory, the OnNavigatedTo event basically becomes a No Op function. We will see how this is implemented shortly.

What Application logic should be in each event?

To make a responsive application, the application developer needs to minimize the logic that occurs in any of the methods or events listed above that would delay the user from being able to interact with the application. Clearly, application logic will need to be included, but it should be deferred to asynchronous, BeginInvoke, or background worker calls.

Application Constructor

  • No user added code from what is added by the default project templates

Application Launch or Activate Events

  • Save the event type for later reference by the application.

    • Do not do any additional work here!

Page Constructor

  • Assign the View model to your DataContext property.

  • Subscribe to the Page PageLayoutUpdated event.

  • Set a flag indicating that the constructor has been called.

Do not do any additional work here!

View Model Constructor

  • Do as little as possible!

OnNavigatedTo Handler

  • Do not do any work on the main UI thread that would delay the page being rendered.

    • Defer all work to either a background thread or use a BeginInvoke call.

  • Include logic to perform required handling for the following cases:

    • Application launch

    • Application Activation when the app was tombstoned.

      • Retrieve the application state from either the PhoneApplicationService or PageApplicationService objects.

    • Application Activation when the app was not tombstoned.

      • This case is essentially a No Op.

    • Application Activation when the application state was not fully saved before exiting.

      • This can occur if the user presses the Start button before you application completes its first time initialization.

Page PageLayoutUpdated Event Handler

  • Unsubscribe to the PageLayoutUpdated event.

  • Schedule any additional required work on a background thread or BeginInvoke call when you are performing an application launch.

OnNavigatedFrom Handler

  • Save required state in either the Phone Application service or Page Application service depending on the structure of your application.

  • Clear the flag indicating that the page constructor has been called.

Special Cases

There are two cases that deserve some additional comments as they are easy to not handle correctly.

The application is tombstoned before it fully initializes on Launch

In the normal flow of an application, it will complete the Page OnNavigatedTo event, receive the Page PageLayoutUpdated event, and finish any initialization required by the application. When the user tombstones the application, the application would save its state by way of either the PhoneApplicationService or PageApplicationService classes. However, if the application was interrupted before it fully initialized, the application may not have been able to save its state correctly. This means that when the application is activated, some or all of the application state will not be able to be retrieved correctly. The application will need to check for this case and perform the required application launch initialization logic.

Determining if the application state was fully saved

The Unit Converter application saved and restored state via the PhoneApplicationService class. The code for the saving/restoring of state can be found in the ApplicationState.cs file

Application state is saved by using the following two functions. The state of the main application page, conversion selection page, the available conversion units and user favorites are saved.

 internal static void AddAppObjects(bool categoryPage)
        {
            AddObject(MainPageState, MainPageInformation);
            AddObject(SupportedConversionsState, SupportedConversions);
            if (categoryPage)
            {
                AddObject(CategoryPageState, CategoryPageInformation);
            }
            AddObject(FavoritesState, Favorites);
        }
 private static void AddObject(string key, object data)
        {
            if (PhoneApplicationService.Current.State.ContainsKey(key))
            {
                PhoneApplicationService.Current.State.Remove(key);
            }
            PhoneApplicationService.Current.State.Add(key, data);
        }

Application state is restored by using the following functions:

 internal static bool RetrieveAppObjects(bool categoryPage)
        {
            bool allObjectsNonNull = false;
            MainPageInformation =  RetrieveObject(MainPageState);
            SupportedConversions = RetrieveObject(SupportedConversionsState);
            Favorites = RetrieveObject(FavoritesState);
            if (SupportedConversions != null &&
                 MainPageInformation != null &&
                 Favorites != null)
            {
                allObjectsNonNull = true;
                AppActivatedInitialization();
                if (categoryPage)
                {
                    CategoryPageInformation = RetrieveObject(CategoryPageState);
                    allObjectsNonNull = CategoryPageInformation != null ? true : false;
                }
            }
            return allObjectsNonNull;
        }


        private static T RetrieveObject(string key)
        {
            T data = default(T);
            if (PhoneApplicationService.Current.State.ContainsKey(key))
            {
                data = (T)PhoneApplicationService.Current.State[key];
            }
            return data;
        }

In the function RetrieveAppObjects, we return a bool depending on whether all of the retrieved objects are non-null. If any of the saved objects are null, this indicates that we could not retrieve the full state of the application. This means that we need to do a full application initialization.
In the ProcessNavigatedToEvent method in the view model class, we see the following snippet logic that checks whether the state of the application was restored fully. If it was not, then we need to perform the full application initialization process.

 if (ApplicationState.RetrieveAppObjects(false))
            {
                this.RefreshStateFromAppState();
                this.AllowNavigation = true;
            }
            else
            {
// Slight possibility that we did not complete 1st time init because of 
// of a app deactivate immediately after start. Protect against this and
// perform application 1st time startup sequence.
                this.SetDefaults();
                this.DeferStartup(notifyOfLoadCompleted);
            }

The application is activated but the application was not tombstoned

This case can occur if the user presses the Start and Back buttons on the phone in quick succession. In this case, the application received a Deactivate event and the system was starting to save the state of the application to perform an application tombstone. Before this operation is completed, the app Activated event is received. The system knows that the application was not removed from memory, so the flow of execution is different. Specifically:

  • The app constructor is not called.

  • The page constructor is not called.

The only way for the application to determine if this condition has occurred is to set a flag to indicate if the page constructor has been called. If you notice in the above section, this flag was set in the page constructor, and cleared in the OnNavigateFrom event. In this case, we will receive the OnNavigatedTo event, but we will see that the page constructor was not called. This tells us that our application was not tombstoned.
In the ProcessNavigatedToEvent method in the view model class, we see the following snippet logic that checks for this condition.

  if (ApplicationState.ApplicationStartup == AppOpenState.Activated &&
                 !isPageActivated)
            {
// We are returning to the application, but we were not tombstoned.
                ApplicationState.AddTimeLog(new TimeLog("Main Page Nav.To Done. No TS"));
                ApplicationState.ApplicationStartup = AppOpenState.None;
                return;
            }

In this case, we should perform the following actions:

  • Any small housekeeping chores

  • Exit the function doing nothing else. All objects are already created, and there is no need to do anything.

The best way to verify that you are exercising this case is on device. After your application is running, Press the Start and Back buttons in quick succession (about 0.5 seconds apart). If the application shows on screen almost immediately, you will know that you have tested this case. If you wait a little longer between the button presses, then you will notice that it will take a longer time to load the application, since it was fully tombstoned.




Putting it all together

The code snippets and sample attached to this entry are for the UnitConverter application from Microsoft that is available in the Windows Phone Marketplace. The complete source code for the Unit Converter can be found in a starter kit which may be downloaded here. This application does not have any network access, so it is useful to demonstrate the concepts we have been discussing.



For reference, the main page of the UnitConverter application is shown here. The two buttons at the bottom of the page navigate to a second page, and store the current conversion settings to isolated storage.

The startup path for this application has been optimized to display the main page as quickly as possible. Two operations were deferred until after the initial page render.

  • The conversion categories are loaded from a XML file stored in the XAP file.

  • The user’s saved Favorite conversions are read from isolated storage.

To display the initial page before these file reads have completed, a default set of units had to be hard coded into the application. This allowed the page to be shown immediately. However, until the conversions and favorites are read, we can’t allow the user to navigate to the conversion selection page or updated the saved favorite list because we don’t have the required information available yet. The buttons at the bottom of the page are disabled until the read operations have completed.

The relevant sections of the application in regard to application startup and activation will be shown next. A small amount of common logic for pages was factored into a base class for the pages in the application. This class is PageCommon.cs and you will see this class in the full code. For the code snippets, all page functionality is shown in the MainPage class.
An enumeration was defined in the application to keep track of how the application was started or if the application was doing an internal page navigation. This enumeration is defined as:

  1.     public enum AppOpenState
        {

  2.         None,

  3.         Launching,

  4.         Activated,

  5.        Deactivated,
           Closing
        }

The None state is used to identify that we are doing a page navigation between pages of the application and not processing a system event such as launch or activated. The variable that stores this state is called ApplicationState.ApplicationStartup and you will see this referenced in the code.

These code snippets do not show the saving/restoring of state via the PhoneApplicationService class, but you can see this in the full code download. A serializable class object for the main page state, conversion selection page state, and the favorite list are created and saved/restored as required.

Application Execution Path tracing

Logging was added so that we could trace the execution of the startup path, as well as some basic performance metrics of when these functions and event were called. Here are the results for the application launch path as well as the activated cases with and without the tombstoning of the application. Simple time stamping was included from a Windows Phone device to see when each of the methods/events occurred in the execution path.

Application Launch

Application Activated, with Tombstoning

Application Activated, without Tombstoning

Event

Time

App Constructor

0:0

App Launching Event

0:172

Page Constructor

0:276

OnNavigatedTo

0:577

PageLayoutUpdated

0:967

Conv. load Completed

1:122

Favorites Loaded

1:169




Event

Time

App Constructor

0:0

App Activated Event

0:281

Page Constructor

0:402

OnNavigatedTo

0:683

PageLayoutUpdated

1:063




Event

Time

App Activated Event

0:0

OnNavigatedTo

0:001




In the Application launch case, the last two entries were for reading the conversions file from the XAP file as well as reading isolated storage for the stored favorites. These operations were deferred after the page render.

In the Activation case where the application was tombstoned, there was no need to read the conversions file or favorites since these data structures were restored from the PhoneApplicationService class.

In the Activation case where the application was not tombstoned, we see how that the application constructor and page constructors were not called.




Code snippets

The code snippets are organized by the files in the application. The flow of execution was listed in the preceding table.

App.xaml.cs

Only relevant sections related to the application startup and activation/deactivation path are included here

The app constructor is the default created by the Phone application templates and is not shown here.

The event type is saved in the Launching, Activated, and Deactivated events.


        private void Application_Launching(object sender, LaunchingEventArgs e)
        {
            ApplicationState.ApplicationStartup = AppOpenState.Launching;      

  }

     
        private void Application_Activated(object sender, ActivatedEventArgs e)
        {
            ApplicationState.ApplicationStartup = AppOpenState.Activated;        

}

    
        private void Application_Deactivated(object sender, DeactivatedEventArgs e)
        {
            ApplicationState.ApplicationStartup = AppOpenState.Deactivated;
        }
MainPage.xaml.cs

  • Only relevant sections related to the application startup and activation/deactivation path are included here.

  • A Boolean is created to indicate if the page has been activated, i.e. if the constructor has been called.

  • This flag is cleared in the OnNavigatedFrom method

  • We subscribe to the PageLayoutUpdated event and once the event has been received, we will unsubscribe to this event.

  • The logic for OnNavigatedTo is in the view model.

  • The view model function DeferStartup is where the read of the conversions xml file and the isolated storage read occur.

  • When the deferred execution has completed, the SignalFavoritesAreLoaded function is called, which enables the UI controls, which enables the application to switch between pages, and saves favorites.

  • The view model function SyncStateToAppState saves the application state to the PhoneApplicationService.

    public partial class MainPage : PageCommon
    {
        protected bool IsPageActivated { get; private set; }
        internal MainPageViewModel viewModel = new MainPageViewModel();

        public MainPage() : base()
        {
            this.DataContext = this.viewModel;

this.LayoutUpdated += new EventHandler(this.PageLayoutUpdated);
            this.IsPageActivated = true;

            InitializeComponent();
        }

        protected  void PageLayoutUpdated(object sender, EventArgs e)
        {
            this.LayoutUpdated -= new EventHandler(this.PageLayoutUpdated);
            if (ApplicationState.ApplicationStartup == AppOpenState.Launching)
            {
                this.viewModel.DeferStartup(this.SignalFavoritesAreLoaded);
                ApplicationState.ApplicationStartup = AppOpenState.None;
            }
        }

        
        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            base.OnNavigatedFrom(e);
            this.IsPageActivated = false;
            this.viewModel.SyncStateToAppState();
            ApplicationState.AddAppObjects(false);
        }
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            this.viewModel.ProcessNavigatedToEvent(this.IsPageActivated,
                this.SignalFavoritesAreLoaded);
        }
        private void SignalFavoritesAreLoaded()
        {
            Dispatcher.BeginInvoke(() => this.viewModel.AllowNavigation = true);
        }

MainPageViewModel.cs

  • Only relevant sections related to the application startup and activation/deactivation path are included here.

  • In the page constructor, the selection of a graphic depending on whether the theme is light or dark is selected. This has to be done before we display the page.

    • ConversionImageSource is a data bound property to one of the buttons on the main page.

  • Handling of the Navigated To event

  • Note that all the cases discussed earlier are handled in this function.

  • The AllowNavigation flag controls whether the buttons at the bottom of the page are enabled or not.

  • Deferring of work to a background thread to allow the UI to render as quickly as possible. The actual work is done in the method DeferStartupWork.

  • See the PageLayoutUpdated handler in the view class where the DeferStartup method is called, or in the ProcessNavigatedToEvent method in the case where the application was not allowed to fully initialize on launch.

  • The saving/restoring of the application state is not shown here.

    private const string SwitchConversionImageDark  = "/Images/switchinuc.png";
   private const string SwitchConversionImageLight = "/Images/switchinuc.light.png";

        private BackgroundWorker worker = new BackgroundWorker();

        internal MainPageViewModel()
        {
            this.ConversionSettings = new CurrentConversion();
            // Chose which graphic should be shown based on the current theme

            this.ConversionImageSource = ApplicationState.IsDarkTheme ?
                SwitchConversionImageLight : SwitchConversionImageDark;
            this.worker.DoWork += new DoWorkEventHandler(DeferStartupWork);

        }
        internal void DeferStartup(Action completed)
        {
            this.worker.RunWorkerAsync(completed);
        }


        private void DeferStartupWork(object sender, DoWorkEventArgs e)
        {
            Action completed = e.Argument as Action;
            lock (threadLock)
            {
                ApplicationState.AppLaunchInitialization();

                this.SetDefaultCategoryAndUnits();
                ApplicationState.Favorites =

FavoriteCollection.LoadFromFile() ?? new FavoriteCollection();
            }

            if (completed != null)
            {
                completed();
            }
        }

        internal void ProcessNavigatedToEvent( bool isPageActivated,Action notifyOfLoadCompleted )
        {
            if (ApplicationState.ApplicationStartup == AppOpenState.Launching)
            {
// Initial application startup.
                this.AllowNavigation = false;
                this.SetDefaults();
// Initialization of the app deferred until the page has rendered. See
// the MainPage_LayoutUpdated handler.
                return;
            }
            if (ApplicationState.ApplicationStartup == AppOpenState.Activated &&
                 !isPageActivated)
            {
                // We are returning to the application, but we were not tombstoned.
                ApplicationState.ApplicationStartup = AppOpenState.None;
                return;
            }

            if (ApplicationState.RetrieveAppObjects(false))
            {
                this.RefreshStateFromAppState();
                this.AllowNavigation = true;
            }
            else
            {
             this.AllowNavigation = false;
// Slight possibility that we did not complete 1st time init because of 
// of a app deactivate immediately after start. Protect against this and
// perform application 1st time startup sequence.
                this.SetDefaults();
                this.DeferStartup(notifyOfLoadCompleted);
            }
            ApplicationState.ApplicationStartup = AppOpenState.None;
        }

Handling network calls to download data during application startup

This is a very common scenario in which an application downloads information from a web service to display to the user. The execution flow is the same as the example above. The biggest challenge is that the information that needs to be displayed to the user needs to be retrieved from the web service. There are three major cases to consider:

First application launch after installation, where there is no possibility of having any previous data saved locally.

Second or greater application launch.

Activation after Tombstoning.

We will look at each of these scenarios separately.

First application launch after installation

Since the application was just installed, there is no possibility to cache any data locally on the device. This means that some data will need to be retrieved before the user will be able to do anything meaningful with the application. One approach that could be used is to use a splash screen while you are loading your content. This approach can work, but be aware that there is no splash screen available when an application is activated.

Another approach that could be considered would be to show your initial page before the content has been loaded and use an overlay or similar mechanism to indicate to the user that content is being loaded.

Non first application launch

In general, the recommendation would be that information retrieved by the application would have been saved locally on the device when the application was run earlier. Now, the application can retrieve content from isolated storage, and display content to the user right away. The application can let the user know that the content is being refreshed, but the application startup experience will be more responsive.

Application activation after tombstoning

In this scenario, the user has been running your application and has now returned to the application. The length of time the application has been deactivated is not known, but often this will be a short amount of time. To have the application be responsive, the application needs to save data via the PhoneApplicationService or PageApplicationService classes and then retrieve the data from these classes. The more information that can be retrieved in this fashion, the more likely it is that the user can interact with the application as soon as possible. The only limitation here is that data saved through this method will be using the Data Contract serializer. Only data types that can be serialized can be saved.

Also, note that there is no splash screen shown in the application activation path so the user will not have that visual indication that you are loading data.

Additional Resources






© Microsoft Corporation. All Rights Reserved. This document is subject to updates.


Share in:

Related:

Windows Phone Silverlight Application Life Cycle for Application Launch, Activate, and Deactivate Events iconCreating a Mobile Phone Application

Windows Phone Silverlight Application Life Cycle for Application Launch, Activate, and Deactivate Events iconPeter Partch Senior Windows Software Developer specializing in User...

Windows Phone Silverlight Application Life Cycle for Application Launch, Activate, and Deactivate Events iconA web application is an application that is accessed over a network...

Windows Phone Silverlight Application Life Cycle for Application Launch, Activate, and Deactivate Events iconAsp net server Controls for Silverlight in the Silverlight 3 sdk

Windows Phone Silverlight Application Life Cycle for Application Launch, Activate, and Deactivate Events iconWindows 10, Windows 7, Windows xp, Windows ce, Windows Mobile, Windows...

Windows Phone Silverlight Application Life Cycle for Application Launch, Activate, and Deactivate Events iconOver 11 years of consulting experience on full life cycle implementations...

Windows Phone Silverlight Application Life Cycle for Application Launch, Activate, and Deactivate Events iconSoftware development life cycle – analysis, design, architecture,...

Windows Phone Silverlight Application Life Cycle for Application Launch, Activate, and Deactivate Events iconApplication: We must receive one completed Rental Application from...

Windows Phone Silverlight Application Life Cycle for Application Launch, Activate, and Deactivate Events iconOf progressive experience in Object-Oriented Analysis and Design...

Windows Phone Silverlight Application Life Cycle for Application Launch, Activate, and Deactivate Events iconAround 6 Years of progressive experience in all phases of software...




forms and shapes


When copying material provide a link © 2017
contacts
filling-form.info
search