Managing app lifecycle
so your apps feel "always alive"
Tuesday, April 10,
2012 10:00 PM
The
app lifecycle model in Windows 8 means that users no longer need to manage
which apps are running. It also makes it easy for developers to craft a great
user experience that doesn’t affect the device’s battery or performance when
the app is in the background. Using the new lifecycle events, your app will
always feel alive, even though it never runs when it is off-screen.
Today,
batteries often run low on laptops, tablets, and phones, because all of us tend
to leave apps running even when we’re not using them. We do this for
convenience and to switch quickly between apps.
We
had this in mind as we developed the lifecycle model for Metro style apps in
Windows 8 – keeping apps responsive, preserving battery life, and providing
excellent, consistent performance. Metro style apps are all about full-screen,
immersive experiences. As such, the new lifecycle model in Windows 8 focuses on
the apps in the foreground, ensuring that the experience the user is actively
engaged and gets the full power of the device. In this post, I’ll walk you
through the new states of the lifecycle model and what you need to do to make
your app great.
Metro style app lifecycle
Your
Metro style app is in one of 4 lifecycle states at any given time: not
running, running , suspended or terminated.
As your app transitions between states, it receives lifecycle events that help
you provide a consistent and high performance experience to your users.
This
diagram shows how a Metro style app transitions between states:
All
Metro style apps move through these states as users launch apps, switch among
them, and close them. Your app will likely move between the running and suspended states
quite often as users switch between apps. So, your app must handle the
lifecycle events.
As
your app transitions among lifecycle states, it receives these lifecycle
events:
Event
|
From
|
To
|
activated
|
not running
|
running
|
suspending or checkpoint (WinJS)
|
running
|
suspended
|
resuming
|
suspended
|
running
|
Suspend
In
general, Metro style apps stop running when the user switches to another app.
Windows suspends your app when it is not in the foreground. When your app is
suspended, it is frozen in memory. It can’t run in this state, but Windows can
instantly resume it when the user returns to it. In this way, Windows gives the
foreground app better use of system resources and ensures apps in the
background can’t drain the user’s battery.
When
your app moves out of the foreground, Windows waits for a few seconds to allow
quick switching back to the app, then tries to suspend the app. Your app must
be registered for the suspending or checkpoint (JavaScript)
events, which it receives when Windows wants to suspend it. This is an
important time for your app; use this opportunity to save app data that must be
kept in persistent storage. Usually, your app is resumed as is, and you won’t
need your persisted data because they are still in memory. But you need to
store this data in case Windows terminates your app to free system resources.
Save enough app data to bring users back to the place in your app where they
were when the app was suspended. This way, your customers perceive your app as
always alive and running.
If
your app doesn’t return from its suspending event handler within 5 seconds of
receiving the suspending event, Windows will terminate it. It’s important not
to do any heavy operations in your suspending event handler. Save your app data
and return quickly.
In
this post, we use a stocks app as an example. This app may use the suspending
event to save the last stock that the user was viewing, and the time range for
a stock chart. Then, if the app is terminated, it can restart to the exact same
view that the user was looking at the last time they saw the app. For example,
the recommendation for a stocks app is to use this as another opportunity to
send a local tile notification so that the app’s tile is updated with the
latest info before Windows suspends it.
Handling suspend in JavaScript
If
you write a Metro style app using the Windows Library for JavaScript (WinJS),
you can use the checkpoint event to handle suspending.
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);
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);
This
is just an overview. For more info, see How to suspend an app (JavaScript
and HTML) on the Dev Center.
Handling suspend in XAML
If
you write a Metro style app using XAML and C#, you can use the Suspending event
on the application object to handle app suspension.
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();
}
{
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();
}
Again,
this is an overview. For more info on how to handle suspend in XAML and C# see How to suspend an app (VB/C#/C++
and XAML) on the Dev Center.
Resume
When
your app is resumed, it continues from the state that it was in when Windows
suspended it. To be specific: app data and state are kept in memory while the
app is suspended, so when it’s resumed, everything is as it was when the app
was suspended. You don’t need to restore any saved data explicitly when
receiving the resuming event.
But
you want your app to appear to be always alive. For this, it has to be
connected and display the latest data. It is possible that your app stays in a
suspended state for quite a long time before it is resumed. Data or network
connections could become stale and may need to be refreshed when your app
resumes. When a user brings your app back to the foreground, your app receives
a resumingevent. You can refresh the app content and reconnect
network resources when your app receives this event.
In
our example stocks app, resume is the right place to refresh all the cached
stock data that the app had before it was suspended. The previous data could be
hours or even days old. The user perception that their app is always alive is
broken if the user sees this old data. On resume, our stocks app must update
all of its data. This way the user sees the latest stock prices, charts, and
news articles each time the app is brought to the foreground.
Handling Resume in JavaScript
In
JavaScript, you can use the Windows Runtime resuming event in
the Windows.UI.WebUI.WebUIApplication namespace. This is a
specialized resuming event meant only for JavaScript apps.
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);
//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);
For
more info see How to resume an app (JavaScript
and HTML) on the Dev Center.
Handling Resume in XAML
If
you write a Metro style app using XAML and C#, you can use the Resuming event
on the application object to handle app resume.
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);
}
{
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);
}
For
more info on how to handle resume in VB/C#/C++ and XAML, see How to resume an app (VB/C#/C++ and
XAML) on the Dev Center.
Activation
Activation
is all about how your app gets launched. It serves many purposes in a Metro
style app. For more details on how you can use Metro style app activation to
handle contracts, see our earlier post, Activating Windows 8 contracts in
your app. Here we focus on how you can use activation to restore
previously saved data in the case that Windows terminated your app and then the
user relaunched it.
Windows
can terminate your app after it has been suspended for a number of reasons. For
example: the user manually closes your app, or signs out, or the system is
running low on resources (some apps, such as games, can be pretty resource
intensive!). If the user launches your app after Windows terminated it, it receives
an activated event and the user sees your app’s splash screen
until the app is activated. You can use this event to determine whether your
app needs to restore the data it saved when it was last suspended, or if you
must load your app’s default data. The activated event
arguments include a PreviousExecutionState property that tells
you the state your app was in before it was activated. This property is one of
the values of theWindows.ApplicationModel.Activation.ApplicationExecutionState enumeration.
Reason for termination
|
PreviousExecutionState value
|
Action to take
|
Terminated by the system (because
of resource constraints, shut down, reboot, etc.)
|
Terminated
|
Restore session data
|
Closed by the user
|
ClosedByUser
|
Start with default data
|
Unexpectedly terminated, or app has not run since the user’s session started
|
NotRunning
|
Start with default data
|
PreviousExecutionState could also have a value of Running or Suspended,
but in these cases your app was not previously terminated and therefore you
don’t have to worry about restoring data.
When
your app is activated and its PreviousExecutionState was Terminated,
you must restore your saved session data to make the app appear just as it was
when the user last looked at it. If the user closed the app manually, the app
unexpectedly terminated or has not yet been run in the current session, you
must ignore the previous session data and start the app up with its default
view.
Our
example stocks app uses the activated event to bring back the
stock and chart info that it saved when it was suspended. The app also
refreshes its cached network data. This way, the user sees the same stock that
they saw when they switched away from the app, but the stock’s prices, charts,
and news articles are all up to date.
Handling Activation in JavaScript
If
you write a Metro style app using the Windows Library for JavaScript (WinJS),
you can use the activated event to handle activation.
In
the activated event handler code, your app can check the sessionState object
to determine if it should load saved data or if it should display the default
home view. SessionState determines the last state of your app
automatically by examiningeventArgs.detail.previousExecutionState. If sessionState is
populated, use it to restore your session data, otherwise use your app’s
default data.
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);
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);
For
more info on how to handle activation in JavaScript, see How to activate an app (JavaScript
and HTML) on the Dev Center.
Handling activation in XAML
In
a Metro style app using XAML and C#, you can override the OnLaunched event
to handle activation a basic activation from a tile.
In
the OnLaunched event handler code, your app can check the PreviousExecutionState on
the event arguments. If it equalsTerminated, restore the
data you saved in the Suspending event. If it is a different
value, use your app’s default data.
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();
}
{
// 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();
}
For
more info on how to handle activation in XAML, see How to activate an app (VB/C#/C++
and XAML) on the Dev Center.
Tips for creating a great app lifetime
experience
Now
that you’ve got all the basics, here are some tips to help you build a great
lifetime experience for your app that will keep it feeling always alive and
fresh for your users.
Sometimes it’s best to start fresh
If
it’s been a while since the user last looked at your app, sometimes it’s best
to reset the app to its default view. It’s up to you to figure out how long is
too long, but if the content of your app would look old or stale, we recommend
you navigate your app back to its home view. This makes your app appear more
intelligent to your users.
For
example, if you are building a news reader app, it is likely your app will be
suspended after the user switches away from it. Sometime later, when the user
returns to your news reader app, the app is resumed. In your resume handler, check
how old the current article is to determine if it is now stale. If the article
is too old, display your default home view instead of the old article.
Save the right data at the right time
Always
save important data incrementally throughout the life of your app. Because your
app has only up to five seconds to run suspending event handler code, you need
to ensure that your important app data has been saved to persistent storage by
the time it is suspended.
There
are two types of data for you to manage as you write your app: session
data and user data. Session data is temporary data that is
relevant to the user’s current experience in your app. For example, the current
stock the user is viewing, the current page the user is reading in an eBook or
the scroll position in a long list of items. User data is persistent and must
always be accessible to the user, no matter what. For example, an in-progress
document that the user is typing, a photo that was taken in the app or the
user’s progress in your game.
Make
sure that by the time your app is suspended, it saved both data types to
persistent storage.
Restoring session data
Users
will expect that a Metro style app will generally stay as they left it when
they last used it. From the developer perspective, when your app is resumed
from a suspended state or activated from a not running state, it is often
appropriate to restore your previously saved session data.
For
example, if your app includes shopping cart functionality and the user added
items to the cart and then switched away from your app, it would make sense to
maintain those items in the cart when the user resumes or reactivates the app.
In
another example, consider an app that shows news articles. If the user was
viewing a specific article, then switched to another app, the user will expect
to see the article they were viewing when they come back to your app.
Release exclusive resources in your suspending event handler
If
your app has acquired any exclusive resources during execution (such as file
handles or references to external devices), it must release those resources
when it receives the suspending event. Additionally, your app
must reclaim those exclusive resources when it receives the resuming event
if it needs them to continue.
Don’t close your app!
Metro
style apps in Windows 8 must never close themselves or present app UI to allow
a user to close your app. Suspending and terminating apps is handled by Windows
on the user’s behalf to maintain system performance and battery life. If users
want to close your app, they can do so by swiping from the top to the bottom of
the screen or by pressing ALT+F4.
In closing
By
using 3 events—suspending, resuming and activated—your
app will always appear to be alive to your users. But at the same time, it will
never drain their battery unnecessarily or reduce their system’s performance
when they are not using it. In the world of slimmer, more mobile devices, the
new Metro style app lifecycle lets your app shine on any device.
Leave your comments and suggestions at admin@exploresilverlight.com
Cheers!
Vinod
No comments:
Post a Comment
Send us your comment related to the topic mentioned on the blog