注:本系列学习帖子我在DevDiv.com移动开发社区原创首发
转载请注明出处:BeyondVincent(破船)@DevDiv.com
如果你有什么问题也可以前往交流
下面是首发地址:
[DevDiv原创]Windows 8 Metro App开发Step by Step---(13个学习帖子)
引子:
在本系列学习文章刚开始的帖子开发环境搭建与HelloWorld中,我曾给大家简单的介绍了一下应用程序生命周期(应用程序的生命周期主要就是通过App.xaml.cs文件进行处理),但没有展开详细的介绍,随着学习的深入,开发的需求和增强用户体验,我们有必要熟悉应用程序的生命周期。
我查阅了一下网络上的可用资源,有一些相关生命周期的资料,但是内容都出自微软的官方博客,由于官方博文中对此进行了详细的讲解,不仅有英文,中文的也有,非常值得我们学习。在此我就直接引用过来,供大家学习参考。在文章的最后,我会贴上一些有用链接。
本文章目录结构:
Metro 风格应用程序的生命周期
打造出色应用程序生存期体验的提示
结束语
废话少说,直接上博文
管理应用程序生命周期,让应用程序始终充满“生命活力”
Windows 8 中的应用程序生命周期模型意味着用户无需再管理哪些应用程序正在运行。它还使开发人员能够轻松打造当应用程序在后台运行时不会影响设备的电池电量或性能的出色用户体验。使用新的生命周期事件,用户将感觉您的应用程序始终处于运行状态,即使它在位于屏幕之外时从不运行。
如今,便携式计算机、平板电脑和手机上的电池电量经常不足,因为即使我们不使用应用程序,往往也会保持应用程序处于运行状态。我们这样做主要是为了方便使用和在应用程序之间实现快速切换。
为 Windows 8 中的 Metro 风格应用程序开发生命周期模型时我们牢记以下几个方面:保持应用程序响应能力、节省电池电量并提供出色且一致的性能。Metro 风格应用程序关键在于全屏沉浸式体验。因此,Windows 8 中新的生命周期模型重点关注前台应用程序,确保积极主动的用户体验并充分实现设备的全部价值。在本博文中,我将带您浏览生命周期模型的新状态以及为了使应用程序出色运行您需要做的工作。
Metro 风格应用程序的生命周期
在任意给定时间,您的 Metro 风格应用程序都处于以下四种生命周期状态之一: 未运行 、 正在运行 、 已挂起 或 已终止 。当应用程序在不同状态之间切换时,它会收到生命周期事件,这些事件可帮助您向用户提供一致且高性能的体验。
下图显示了 Metro 风格应用程序如何在各状态之间切换:
当用户启动 Metro 风格应用程序、在应用程序之间切换以及关闭应用程序时,所有这些应用程序都会经历这些状态。当用户在应用程序之间切换时,应用程序很可能频繁在 正在运行 和 已挂起 状态之间切换。因此,应用程序必须处理生命周期事件。
当您的应用程序在各个生命周期状态之间切换时,它会收到以下生命周期事件:
挂起
通常情况下,Metro 风格应用程序会在用户切换到另一应用程序时停止运行。Windows 会挂起不在前台的应用程序。当您的应用程序挂起时,它在内存中处于冻结状态。处于此状态时,它无法运行,但如果用户返回该应用程序,Windows 可立即将其恢复。这样,Windows 就可以让前台应用程序更好地使用系统资源,并确保后台应用程序不会耗尽用户的电池电量。
当您的应用程序离开前台时,Windows 会等待几秒钟以便能够快速切换回该应用程序,然后才尝试将其挂起。您的应用程序必须注册 suspending 或 checkpoint (JavaScript) 事件,当 Windows 需要将其挂起时,它会收到这些事件。这是应用程序的重要时刻;可利用此机会保存必须保留在持久存储中的应用程序数据。通常,您的应用程序会按原样恢复,您不需要持久留存的数据,因为它们仍然在内存中。但您需要存储这些数据以防 Windows 为了释放系统资源而终止应用程序。保存足够的应用程序数据可让用户返回到当应用程序挂起时他们在应用程序中所处的位置。这样,您的客户就会感觉您的应用程序始终处于运行状态。
如果应用程序没有在收到挂起事件后的 5 秒内从挂起事件处理程序中返回,Windows 会将其终止。切勿在挂起事件处理程序中执行任何繁重操作,这一点非常重要。应保存应用程序数据并快速返回。
在本博文中,我们以股票应用程序为例。该应用程序可以使用挂起事件来保存用户上次查看的股票以及股价图的时间范围。这样一来,如果应用程序被终止,它就可以正好重新启动到用户上次查看该应用程序时所看到的同一视图。例如,针对股票应用程序的建议是,借此机会发送本地磁贴通知,以便在 Windows 挂起应用程序之前,应用程序的磁贴能够使用最新信息进行更新。
在 JavaScript 中处理挂起
如果您使用 Windows JavaScript 库 (WinJS) 编写 Metro 风格应用程序,则可以使用 checkpoint 事件处理挂起。
var app = WinJS.Application;
function checkpointHandler() {
// The checkpoint event gives us the chance to save application data.
// In this case, we save the current stock info that the user is viewing.
app.sessionState.lastSeenStock = selectedStock;
app.sessionState.lastSeenRange = selectedRange;
// Send client side notifications
Tile.sendTileUpdate(selectedStock, stockInfo.change, stockInfo.lastSale,
stockInfo.lastSaleTime, stockInfo.open);
}
app.addEventListener("checkpoint", checkpointHandler);
这只是一个概要。有关详细信息,请参阅开发中心中的 如何挂起应用程序(JavaScript 和 HTML) 。
在 XAML 中处理理挂起
如果您使用 XAML 和 C# 编写 Metro 风格应用程序,则可以对应用程序对象使用 Suspending 事件来处理应用程序挂起。
public App()
{
InitializeComponent();
this.Suspending += new SuspendingEventHandler(OnSuspending);
}
async protected void OnSuspending(object sender, SuspendingEventArgs args)
{
// The Suspending event gives us the chance to save application state
// In this case, we save the current stock info that the user is viewing
// Because writing to a file is asynchronous, we grab a deferral which ensures
// that suspending doesn’t complete until our file write is complete
SuspendingDeferral deferral = args.SuspendingOperation.GetDeferral();
// Here we create a SuspensionManager class which handles adding session data
// to a Dictionary and then serializing that data to a file
SuspensionManager.SessionState["lastSeenStock"] = stock;
SuspensionManager.SessionState["lastSeenRange"] = range;
await SuspensionManager.SaveAsync();
// Send client side notifications
Tile.SendTileUpdate(stock, stockInfo.Change, stockInfo.LastSale,
stockInfo.LastSaleTime, stockInfo.Open);
deferral.Complete();
}
这同样只是一个概要。有关如何在 XAML 和 C# 中处理挂起的详细信息,请参阅开发中心中的 如何挂起应用程序(VB/C#/C++ 和 XAML) 。
恢复
当应用程序恢复时,它将从 Windows 将其挂起它所处的状态继续进行。具体说就是:当应用程序挂起,应用程序数据和状态保留在内存中,因此当它恢复时,一切都保持它挂起时的状态。在收到 resuming 事件时,您不需要明确还原任何已保存的数据。
但您希望您的应用程序看起来始终处于运行状态。为此,它必须保持连接并显示最新数据。但是在恢复之前,您的应用程序可能会在挂起状态停留很长时间。因此数据或网络连接可能会过时,在应用程序恢复时,可能需要刷新连接。当用户将您的应用程序切换到前台时,它会收到 resuming 事件。您可以在应用程序收到此事件时刷新应用程序内容并重新连接网络资源。
在我们的示例股票应用程序中,将在恢复时刷新应用程序在挂起前所具有的所有缓存股票数据。之前的数据可能已存在数小时甚至数天之久。如果用户看到这些旧数据,他们就会意识到所用应用程序并非始终处于运行状态。因此在恢复时,我们的股票应用程序必须更新其所有数据。这样,应用程序每次切换到前台时,用户都会看到最新的股票价格、股价图和新闻文章。
在 JavaScript 中处理恢复
在 JavaScript 中,您可以在 Windows.UI.WebUI.WebUIApplication 命名空间中使用 Windows 运行时 resuming 事件。这是专门用于 JavaScript 应用程序的 resuming 事件。
function resumingHandler() {
//Update the selected stock with the latest news, stock info, and chart data
News.requestNews(stock);
Api.getStockInfoData(stock).then(function(data){displayStockInfo(data); });
Api.getHistoryData(range).then(function (chartData)
{CanvasChart.drawChart("chartCanvas", chartData, Chart.getChartOptions(false));});
// Send client side notifications
Tile.sendTileUpdate(stock, stockInfo.change, stockInfo.lastSale,
stockInfo.lastSaleTime, stockInfo.open);
}
Windows.UI.WebUI.WebUIApplication.addEventListener("resuming", resumingHandler);
有关详细信息,请参阅开发中心中的 如何恢复应用程序(JavaScript 和 HTML) 。
在 XAML 中处理恢复
如果您使用 XAML 和 C# 编写 Metro 风格应用程序,则可以对应用程序对象使用 Resuming 事件来处理应用程序恢复。
public App()
{
InitializeComponent();
this.Resuming += new EventHandler<object>(App_Resuming);
}
async private void App_Resuming(object sender, object e)
{
//Update the selected stock with the latest news, stock info, and chart data
News.RequestNews(stock);
Data data = await Api.GetStockInfoDataAsync(stock);
Api.DisplayStockInfo(data);
Chart chartData = await Api.GetHistoryDataAsync(range);
CanvasChart.DrawChart("chartCanvas", chartData, Chart.GetChartOptions(false));
// Send client side notifications
Tile.SendTileUpdate(stock, stockInfo.Change, stockInfo.LastSale, stockInfo.LastSaleTime, stockInfo.Open);
}
有关如何在 VB/C#/C++ 和 XAML 中处理恢复的详细信息,请参阅开发中心中的 如何恢复应用程序(VB/C#/C++ 和 XAML) 。
激活
激活与您应用程序的启动方式息息相关。在 Metro 风格应用程序中它起到多方面的作用。有关如何使用 Metro 风格应用程序激活处理合约的更多详细信息,请参阅我们之前的博文 在您的应用程序中激活 Windows 8 合约 。本文中我们重点介绍当 Windows 终止您的应用程序,随后用户又重新启动它时,如何使用激活来还原之前保存的数据。
Windows 可能会出于多个原因终止已挂起的应用程序。例如:用户手动关闭应用程序或注销,或者系统的资源不足(诸如游戏之类的应用程序可能需要大量资源!)。如果用户在 Windows 终止应用程序后启动应用程序,它会收到 activated 事件,用户会看到应用程序的初始屏幕,直到应用程序被激活。您可以使用此事件确定应用程序是否需要还原上次挂起时保存的数据,或者您是否必须加载应用程序的默认数据。 activated 事件参数包含一个 PreviousExecutionState 属性,该属性会告诉您在激活之前应用程序所处的状态。该属性的值是 Windows.ApplicationModel.Activation.ApplicationExecutionState 枚举值之一。
PreviousExecutionState 的值还可以是 Running 或 Suspended ,但在这些情况下,您的应用程序之前并未终止,因此您不必考虑是否需要还原数据。
当应用程序已激活并且其 PreviousExecutionState 值为 Terminated 时,您必须还原已保存的会话数据,以使应用程序完全保持用户上次看到的样子。如果用户手动关闭应用程序、应用程序意外终止或者在当前会话中尚未运行,则您必须忽略之前的会话数据并使用默认视图启动应用程序。
我们的示例股票应用程序使用 activated 事件重新显示挂起时所保存的股票和股价图信息。该应用程序还刷新其缓存的网络数据。这样,用户看到的就是他们离开该应用程序时所查看的股票,但股票价格、股价图和新闻文章全都是最新的。
在 JavaScript 中处理激活
如果您使用 Windows JavaScript 库 (WinJS) 编写 Metro 风格应用程序,则可以使用 activated 事件处理激活。
在 activated 事件处理程序代码中,您的应用程序可以检查 sessionState 对象,以确定它是应加载保存的数据,还是应显示默认主页视图。 SessionState 通过检查 eventArgs.detail.previousExecutionState 自动确定应用程序上次的状态。如果 sessionState 已填充,则使用它还原会话数据,否则使用应用程序的默认数据。
var app = WinJS.Application;
function activatedHandler(eventArgs) {
if (eventArgs.detail.kind == Windows.ApplicationModel.Activation.ActivationKind.launch) {
// Check whether the session state variables are valid.
// If so, retrieve the stock and range values saved in the checkpoint handler
if (app.sessionState) {
stock = app.sessionState.lastSeenStock;
range = app.sessionState.lastSeenRange;
}
// If not, use the app's default values
else{
stock = "DOW";
range = "1M";
}
// Initialize the WinJS controls asynchronously behind the app splash screen
// Start retrieving the latest stock data asynchronously after the controls are ready
eventObject.setPromise(WinJS.UI.processAll().then(function() {
Api.initializeUserStocks();
}));
}
}
app.addEventListener("activated", activatedHandler);
有关如何在 JavaScript 中处理激活的详细信息,请参阅开发中心中的 如何激活应用程序(JavaScript 和 HTML) 。
在 XAML 中处理激活
在使用 XAML 和 C# 的 Metro 风格应用程序中,您可以替代 OnLaunched 事件来处理从磁贴基本激活应用程序。
在 OnLaunched 事件处理程序代码中,您的应用程序可以检查事件参数上的 PreviousExecutionState 。如果它等于 Terminated ,则还原您在 Suspending 事件中保存的数据。如果是其他值,则使用应用程序的默认数据。
async protected override void OnLaunched(LaunchActivatedEventArgs args)
{
// Check whether the session data should be restored
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
// Here we've created a SuspensionManager class which handles restoring session
// data from a file and then gives access to that data through a Dictionary
await SuspensionManager.RestoreAsync();
// Retrieve the stock and range values saved in the suspend handler
stock = SuspensionManager.SessionState["lastSeenStock"];
range = SuspensionManager.SessionState["lastSeenRange"];
}
// If not, use the app's default values
else
{
stock = "DOW";
range = "1M";
}
// Start retrieving the latest stock data
Api.InitializeUserStocks();
Window.Current.Activate();
}
有关如何在 XAML 中处理激活的详细信息,请参阅开发中心中的如何激活应用程序(VB/C#/C++ 和 XAML)。
现在您已了解了所有基础知识,下面是一些可帮助您为应用程序打造出色生存期体验以便在用户看来应用程序始终处于活动和最新状态的一些提示。
如果自用户上次查看应用程序已过了很长时间,有时最好将应用程序重置为其默认视图。多久才算很久完全由您决定,但如果应用程序的内容看起来陈旧或过时,则建议您将应用程序恢复为其主页视图。这会使应用程序在用户看来更加智能。
例如,如果您要构建一个新闻阅读器应用程序,在用户从该应用程序切出后,它可能会被挂起。过了一段时间后,当用户回到新闻阅读器应用程序时,应用程序将会恢复。在恢复处理程序中,检查当前文章已存在多长时间,以确定它现在是否已过时。如果文章太旧,则显示默认主页视图而不是旧文章。
在应用程序的整个生命周期中,始终以增量方式保存重要数据。由于应用程序只有最多五秒的时间来运行挂起事件处理程序代码,因此您需要确保在应用程序挂起时,您的重要应用程序数据已保存到持久存储。
在编写应用程序时,您需要管理以下两种类型的数据:会话数据和用户数据。会话数据是应用程序中与用户的当前体验相关的临时数据。例如,用户正在查看的当前股票、用户正在 eBook 中阅读的当前页面或一个很长的项目列表中的滚动位置。用户数据是持久性的,必须始终可供用户访问,无论它们是什么。例如,用户正在键入的进行中文档、在应用程序中拍摄的照片或用户在游戏中的进度。
确保在应用程序挂起时,它已将这两种数据类型保存到持久存储。
用户希望 Metro 风格应用程序通常保持他们上次使用它时所处的状态。从开发人员的角度看,当您的应用程序从挂起状态恢复或从未运行状态激活时,还原之前保存的会话数据通常是合理的。
例如,如果您的应用程序包括购物车功能,并且用户向购物车中添加商品后从应用程序中切出,那么在用户恢复或重新激活该应用程序时维护购物车中的那些商品应该是有意义的。
再举一个例子,假设某应用程序显示新闻文章。如果用户之前正在查看某特定文章,然后切换到另一应用程序,用户会希望当他们回到您的应用程序中时,他们能够看到之前正在查看的文章。
释放挂起事件处理程序中的独占资源
如果应用程序在执行过程中获取了任何独占资源(例如文件句柄或外部设备引用),那么它在收到suspending 事件时则必须释放这些资源。此外,如果您的应用程序需要使用这些独占资源才能继续运行,那么在收到 resuming 事件时,则必须回收这些资源。
Windows 8 中的 Metro 风格应用程序永远不能将其自身关闭或者提供应用程序用户界面让用户关闭您的应用程序。挂起和终止应用程序由 Windows 代表用户进行处理,以维护系统性能和电池寿命。如果用户想要关闭您的应用程序,他们可以通过从屏幕顶部向屏幕底部滑动或者按 Alt+F4 来实现。
通过使用 suspending、resuming 和 activated 这三个事件,对用户而言,您的应用程序看起来始终处于活动状态。但与此同时,在用户不使用应用程序时,它永远不会不必要地耗尽电池电量或降低系统性能。在设备越来越紧凑、移动性越来越强的世界里,新的 Metro 风格应用程序生命周期使您的应用程序在任何设备上都能大放异彩。
本博文链接:
中文版: 管理应用程序生命周期,让应用程序始终充满“生命活力”
英文版: Managing app lifecycle so your apps feel "always alive"
msdn上的一篇文章:应用程序生命周期(Metro style apps)
Application lifecycle (Metro style apps)
How to activate an app (Metro style apps using C#/VB/C++ and XAML)
How to suspend an app (Metro style apps using C#/VB/C++ and XAML)
How to resume an app (Metro style apps using C#/VB/C++ and XAML)