代码改变世界

第三篇 Windows8 Metro管理应用生命周期和状态(摘微软官网)

2012-11-08 14:19  半饱  阅读(1019)  评论(1编辑  收藏  举报

目录
1、应用生命周期简介
2、使用 SuspensionManager
3、保存应用状态
4、还原应用状态

   介绍

在我们返回到代码之前,我们来讨论一下应用的生命周期。激活标记着应用生命周期的开始。在任意给定时间点,应用未应用、正在运行或挂起。

 


应用可在用户离开它或 Windows 进入电量不足状态时挂起。 当应用挂起时,它继续驻留在内存中,以便用户可以快速且可靠切换到该应用。
当应用挂起时,它可以随时恢复运行。Windows 也可以随时终止该应用来为其他应用释放内存或节省电量。
当应用挂起然后恢复运行时,它看上去好像一直在运行。 如果应用被终止,它会停止运行并且从内存中卸载。Windows 会在挂起应用时通知应用,但不会在终止应用时提供其他通知。 这表示应用应处理挂起的事件,使用该事件保存其状态以及立即释放其独占资源和文件句柄。

   使用 SuspensionManager

在创建Windows 8 Metro Style app应用程序中,我们用一个基于“基本页”模板的文件替换了默认的 MainPage 文件。当我们使用“基本页”模板时,Microsoft Visual Studio 向 Common 文件夹中的项目添加多个文件。这些文件之一包含 SuspensionManager 类。SuspensionManager 为帮助程序类,我们使用该类可简化应用的生命周期管理。该类可为你实现很多操作。它会保存和还原托管应用页面的 Frame 的导航状态。在单页应用中,保存导航状态似乎不是非常重要,但在向应用中添加多个页面时该操作就变得非常重要了。它还为每个页面提供了保存并还原其状态的机会。SuspensionManager 序列化页面状态数据并将其写入应用的本地存储中的 XML 文件。
若要使用应用中的 SuspensionManager 类,首先需要注册主应用 Frame。完成操作后,SuspensionManager 可保存和还原导航状态,并且了解有关应用中每个页面的信息。在 App.xaml.cs 的 OnLaunched 方法中创建 Frame 之后,会立即进行注册。
使用 SuspensionManager
1.调用 SuspensionManager.RegisterFrame 方法可注册根 Frame。

 

HelloWorld.Common.SuspensionManager.RegisterFrame(rootFrame, "appFrame");

2.移动 rootFrame 的声明。
在还原 Frame 的状态之前需要进行注册,以便将用于声明和注册 rootFrame 的代码移至还原应用状态的代码之前。

        /// <summary>
        /// Invoked when the application is launched normally by the end user.  Other entry points
        /// will be used when the application is launched to open a specific file, to display
        /// search results, and so forth.
        /// </summary>
        /// <param name="args">Details about the launch request and process.</param>

        protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
            // Do not repeat app initialization when already running, just ensure that
            // the window is active
            if (args.PreviousExecutionState == ApplicationExecutionState.Running)
            {
                Window.Current.Activate();
                return;
            }

            // Create a Frame to act as the navigation context and navigate to the first page
            var rootFrame = new Frame();
            HelloWorld.Common.SuspensionManager.RegisterFrame(rootFrame, "appFrame");

            if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
            {
                //TODO: Load state from previously suspended application
            }

            if (!rootFrame.Navigate(typeof(MainPage)))
            {
                throw new Exception("Failed to create initial page");
            }

            // Place the frame in the current Window and ensure that it is active
            Window.Current.Content = rootFrame;
            Window.Current.Activate();
        }

 

   保存应用状态

在还原 Frame 的状态之前需要进行注册,以便将用于声明和注册 rootFrame 的代码移至还原应用状态的代码之前。
我们需要保存哪些数据以及应何时保存数据?此时,用户可以在页面中更改的唯一事项为其名称。用户还可以单击“Say "Hello"”按钮来生成个性化问候。
通常,在应用中管理的两种数据为:用户数据和会话数据。用户数据保留在会话中且用户必须始终可以访问这些数据。在我们的应用中,nameInputTextBox 的 Text 为用户数据。在应用的整个生命周期内始终不断保存重要的用户数据。由于应用最多只有 5 秒钟来运行挂起事件处理程序中的代码,因此你需要确保当应用挂起时将重要应用数据保存到永久性存储中。
Windows 提供了 Windows.Storage.ApplicationData 对象,有助于我们管理应用数据。 此对象的 LocalSettings 属性会返回 ApplicationDataContainer。我们可以使用此本地 ApplicationDataContainer 来存储会话中保留的用户数据。当用户在本地 ApplicationDataContainer 中键入用户名时,我们在其中存储该名称。
会话数据为临时数据,它与应用中用户的当前会话相关。会话会在以下情形下结束:用户使用“任务管理器”关闭应用,重新启动计算机,注销计算机,或使用关闭手势或 Alt + F4 来关闭应用。 在应用中,greetingOutput TextBlock 的 Text 为会话数据。仅当 Windows 挂起和终止应用时才还原该数据。我们需要保存应用 Frame 的导航状态,以便应用可以还原到其所在的同一页面,以及以便 SuspensionManager 了解要还原其状态的页面。我们还需要保存页面自身的状态。此为我们保存 greetingOutput 文本的位置。我们使用 SuspensionManager 类来保存 Application.Suspending 事件处理程序中的会话状态。
只要持续的用户数据在应用程序中有意义时都会保存该数据。此时,我们处理 TextBox.TextChanged 事件并当用户输入用户名时保存该用户名。
保存用户数据
1.在可扩展应用程序标记语言 (XAML) 或设计视图中,选择已添加到 MainPage.xaml 的 nameInput TextBox。
2.在“属性窗口”中,单击“事件”按钮 (
按钮)。
提示 如果你没有看到“属性窗口”,则按 Alt+Enter 将其打开。
3.在事件列表中找到 TextChanged 事件。在事件的文本框中,键入处理 TextChanged 事件的函数名称。对于本示例,请键入 "NameInput_TextChanged"。
4.按 Enter。事件处理程序方法在代码编辑器中创建和打开,因此你可以添加在事件出现时执行的代码。
5.向在代码隐藏页面中的事件处理程序添加代码。在事件处理程序中,保存 localSettings 中的 nameInput 文本。

        private void NameInput_TextChanged(object sender, TextChangedEventArgs e)
        {
            Windows.Storage.ApplicationDataContainer localSettings = 
                Windows.Storage.ApplicationData.Current.LocalSettings;
            localSettings.Values["userName"] = nameInput.Text;
        }

6.按 F5 可构建并运行应用。当你在文本框中输入名称时会保存该名称。
App.xaml.cs 文件包含 Application.Suspending 事件的处理程序。Windows 即将挂起应用时会调用此事件处理程序。 这是我们保存应用状态以防该应用被终止的时机。我们使用 SuspensionManager 类来简化会话状态保存过程。该类会保存应用的导航状态并为你提供保存活动页面会话状态的机会。
保存会话状态
1.在 App.xaml.cs中,向 OnSuspending 方法签名添加 async 关键字。

2.调用 SuspensionManager.SaveAsync 方法。
调用 SaveAsync 可保存 Frame 的导航状态,然后为 Page 提供保存其内容的机会。

        /// <summary>
        /// Invoked when application execution is being suspended.  Application state is saved
        /// without knowing whether the application will be terminated or resumed with the contents
        /// of memory still intact.
        /// </summary>
        /// <param name="sender">The source of the suspend request.</param>
        /// <param name="e">Details about the suspend request.</param>

        private async void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            //TODO: Save application state and stop any background activity
            await HelloWorld.Common.SuspensionManager.SaveAsync();
            deferral.Complete();
        }

3.在 MainPage.xaml.cs中,向 SaveState 方法添加代码可保存页面状态。
SuspensionManager 类会序列化 pageState 字典并将其保存到 XML 文件。在 pageState 中保存的数据仅为此会话保存。此处保存 greetingOutput 文本。

        /// <summary>
        /// Preserves state associated with this page in case the application is suspended or the
        /// page is discarded from the navigation cache.  Values must conform to the serialization
        /// requirements of <see cref="SuspensionManager.SessionState"/>.
        /// </summary>
        /// <param name="pageState">An empty dictionary to be populated with serializable state.</param>
        
        protected override void SaveState(Dictionary<String, Object> pageState)
        {
            pageState["greetingOutputText"] = greetingOutput.Text;

            // The user name is already saved, so we don't need to save it here.
        }

4.按 F7 可确保应用构建且没有错误。
这就是我们在应用被终止前保存应用状态所需执行的全部操作。现在我们需要了解如何在下次用户启动应用时还原应用状态。

   还原应用状态

之前,我们看到 App.xaml.cs文件包含处理应用激活的代码。可以使用多种不同的方法激活应用。此时我们看看启动激活和 OnLaunched 方法。
只要应用未运行,该应用就会被启动,然后用户激活该应用。当应用启动时,Windows 显示应用的一个初始屏幕。
我们来了解处理应用激活的 App.xaml.cs中的代码。代码定义了 OnLaunched 方法重写。 仅当激活为 Launch 激活时才执行此方法中的代码。(你可以替代其他方法来处理其他种类的激活,但此处我们不执行该操作。有关详细信息,请参阅应用程序生命周期。)
首先,代码会检查以前的执行状态以查看应用是否已在运行。如果在运行,则仅激活当前窗口。

        /// <summary>
        /// Invoked when the application is launched normally by the end user.  Other entry points
        /// will be used when the application is launched to open a specific file, to display
        /// search results, and so forth.
        /// </summary>
        /// <param name="args">Details about the launch request and process.</param>
        protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
            // Do not repeat app initialization when already running, just ensure that
            // the window is active
            if (args.PreviousExecutionState == ApplicationExecutionState.Running)
            {
                Window.Current.Activate();
                return;
            }

如果应用未运行,则代码会创建 Frame 来托管应用页面。向 SuspensionManager 注册 Frame。此为我们在步骤 1 中添加的代码。

            // Create a Frame to act as the navigation context and navigate to the first page
            var rootFrame = new Frame();
            HelloWorld.Common.SuspensionManager.RegisterFrame(rootFrame, "appFrame");

接下来,代码会检查以前的执行状态以查看上次应用如何关闭。如果以前的执行状态为 terminated,则该状态表示上次应用运行,Windows 成功挂起应用,然后终止该应用。在这种情形下,需要还原应用状态。
如果应用未被 Windows 终止,则代码将其视为应用第一次启动。

            if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
            {
                //TODO: Load state from previously suspended application
            }

最后,代码会调用 Frame.Navigate 方法来转至 MainPage,并且激活窗口。由于将添加代码来还原应用的导航状态,因此仅当导航状态未被还原时才修改此代码来调用 Frame.Navigate。

            if (!rootFrame.Navigate(typeof(MainPage)))
            {
                throw new Exception("Failed to create initial page");
            }

            // Place the frame in the current Window and ensure that it is active
            Window.Current.Content = rootFrame;
            Window.Current.Activate();
        }

既然你了解启动应用时发生的情况,我们来看看如何还原应用状态。
还原应用状态
1.在 App.xaml.cs 中,向 OnLaunched 方法签名添加 async 关键字。

protected async override void OnLaunched(LaunchActivatedEventArgs args)

2.如果应用被终止,则调用 SuspensionManager.RestoreAsync 方法。
调用 RestoreAsync 会还原 Frame 的导航状态,然后为 Page 提供还原其内容的机会。

            if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
            {
                //TODO: Load state from previously suspended application
                await HelloWorld.Common.SuspensionManager.RestoreAsync();
            }

3.仅当应用的导航状态未被还原时才修改导航至 MainPage 的代码。

            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored, navigate to the first page.
                if (!rootFrame.Navigate(typeof(MainPage)))
                {
                    throw new Exception("Failed to create initial page");
                }
            }

以下是 OnLaunched 方法的完整代码。

        protected async override void OnLaunched(LaunchActivatedEventArgs args)
        {
            // Do not repeat app initialization when already running, just ensure that
            // the window is active
            if (args.PreviousExecutionState == ApplicationExecutionState.Running)
            {
                Window.Current.Activate();
                return;
            }

            // Create a Frame to act as the navigation context and navigate to the first page
            var rootFrame = new Frame();
            HelloWorld.Common.SuspensionManager.RegisterFrame(rootFrame, "appFrame");

            if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
            {
                //TODO: Load state from previously suspended application
                await HelloWorld.Common.SuspensionManager.RestoreAsync();
            }

            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored navigate to the first page.
                if (!rootFrame.Navigate(typeof(MainPage)))
                {
                    throw new Exception("Failed to create initial page");
                }
            }

            // Place the frame in the current Window and ensure that it is active
            Window.Current.Content = rootFrame;
            Window.Current.Activate();
        }

4.在 MainPage.xaml.cs 中,向 LoadState 方法添加代码可还原页面状态。
a.首先,检查以查看 pageState 字典是否存在且是否具有名为 greetingOutputText 的密钥。如果密钥存在,则使用它还原 greetingOutput 文本。

            // Restore values stored in session state.
            if (pageState != null && pageState.ContainsKey("greetingOutputText"))
            {
                greetingOutput.Text = pageState["greetingOutputText"].ToString();
            }

b.接下来,加载用户名。由于我们希望用户名数据在多个会话上保留,因此我们将其存储在 LocalSettings 应用数据容器中。我们来添加一些代码以查看用户名是否存在,如果存在,则显示该名称。

            // Restore values stored in app data.
            Windows.Storage.ApplicationDataContainer localSettings = 
                Windows.Storage.ApplicationData.Current.LocalSettings;
            if (localSettings.Values.ContainsKey("userName"))
            {
                nameInput.Text = localSettings.Values["userName"].ToString();
            }

以下是 LoadState 方法的完整代码。

        /// <summary>
        /// Populates the page with content passed during navigation.  Any saved state is also
        /// provided when recreating a page from a prior session.
        /// </summary>
        /// <param name="navigationParameter">The parameter value passed to
        /// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested.
        /// </param>
        /// <param name="pageState">A dictionary of state preserved by this page during an earlier
        /// session.  This will be null the first time a page is visited.</param>

        protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
        {
            // Restore values stored in session state.
            if (pageState != null && pageState.ContainsKey("greetingOutputText"))
            {
                greetingOutput.Text = pageState["greetingOutputText"].ToString();
            }

            // Restore values stored in app data.
            Windows.Storage.ApplicationDataContainer localSettings = 
                Windows.Storage.ApplicationData.Current.LocalSettings;
            if (localSettings.Values.ContainsKey("userName"))
            {
                nameInput.Text = localSettings.Values["userName"].ToString();
            }
        }

现在你可以构建并运行应用,然后查看如何保存和还原会话状态。到目前为止,你已测试该应用,方法是在调试模式下运行该应用以及在 Visual Studio 中选择“调试”>“停止调试”停止该应用。但是执行此操作会导致应用执行正常关闭且 Suspending 事件不会出现。幸运的是,Visual Studio 可让你模拟挂起、终止以及还原某个应用。

在 Visual Studio 中模拟挂起、终止以及还原应用
1.按 F5 可在调试模式下运行应用。
2.在输入框中输入你的姓名,然后单击 "Say "Hello""。会显示问候。
3.按 Alt+Tab 可返回到 Visual Studio。
4.在“调试位置”工具栏上的“挂起”按钮旁边,打开下拉菜单。
当调试程序运行时,默认情况下会出现“调试位置”工具栏。如果未看到该工具栏,则单击“视图”>“工具栏”>“调试位置”来显示该工具栏。


5.选择“挂起和关闭”。
Visual Studio 会模拟应用挂起和终止,因此会出现 Suspending 事件且会执行状态管理代码。
6.按 F5 可再次运行应用。应用会还原为其之前状态。
7.在文本框中更改名称,然后单击 "Say "Hello""。
8.按 Alt+Tab 可返回到 Visual Studio。
9.通过选择“调试”>“停止调试”关闭应用。
10.按 F5 可再次运行应用。
现在,用户名被还原,因为用户名在你键入时已进行保存。问候未被还原,因为 Suspending 事件未发生,因此未保存会话状态。

 

  总结与下节摘要

这一节主要讲述内容有:1:使用 SuspensionManager 2:保存应用状态 3:还原应用状态,在下一节中将开始做一些实战开发性的介绍。

如果此文章对您有帮助,不妨点击[推荐]
如果要关注后续的文章请点击[关注]
感谢您的阅读,欢迎转载!转载时别忘记添加来源:http://www.cnblogs.com/CsrNet