Windows 8 keeps users always connected. They can be connected to the internet, cloud services, and their other Windows 8 PCs. Your app can participate in this always connected ecosystem by taking advantage of roaming app data. In this post I tell you more about roaming app data, what it is, why it’s important, and best of all how easy it is to implement in your app.

Why roam data

Roaming personalization settings is key to feeling connected to Windows, and Windows 8 does that for many Windows settings, such as your desktop theme, backgrounds, and browser favorites. But Windows is only a small piece of a user’s personalization. Apps are the cornerstone in creating that always connected experience in Windows 8. It is your apps that bring enjoyment to Windows users, and it is your apps that they spend much of their time using. While our apps such as Bing Weather and Sports have these roaming experiences, we need your help to complete the vision of a connected Windows 8.

Roaming to the cloud is also something cool and exciting that can delight your customers with convenience and help your app stand out from the rest. A great Metro style app with roaming will allow the user to configure it once and use it everywhere, so the user doesn’t have to re-configure the app each time they access it from a different PC It will also help them connect from anywhere by having a continuous experience as they transition from one PC to another.

How we made it easy

Our goal with roaming app data was to make it very easy to create these roaming experiences. We steered away from having you, the developer, manage the sync mechanics because it can be cumbersome and complex. We wanted to make it simple for you to roam everything the user might configure.

To make this happen, Windows 8 has an integrated roaming sync for Application Data for all Metro style apps using the connected Microsoft Account associated with the user. ApplicationData is partitioned into three types of data which we call localities: local, roaming, and temporary. Simply by writing its data to the roaming locality your app can participate in the data being synced with the connected Microsoft account. This means that you don’t need to worry about managing the sync relationship, setting up an identity and login, buy or manage a service, or any of that other messy stuff. Windows takes care of it for you. All you need to focus on is what data to roam and how to design your app to take advantage of these benefits. When users connect to Windows, they also connect to your app.

A flow chart showing how date moves back and forth between your computer, local storage, and cloud storage

User data vs. app data

Before we dive in, it is important when working with roaming experiences to understand the difference between user data and app data. User data is data that a user creates and manages in the course of using the app, such as the user’s documents, music, videos, and pictures. It could also be anything that the user perceives as valuable or that may be shared among apps. This type of data should be stored in one of the KnownFolder libraries, or roamed using the SkyDrive APIs.  Passwords should always be stored and roamed using the PasswordVault. This blog post is scoped to data that the app creates and manages, such as its settings, preferences, and state. These differences between user data and app data and how to roam each of them are summarized in this table.

User data

App data

May be used by multiple apps

Only meaningful to the app that created it

Documents, music, pictures, exported data

Settings, preferences, context, app state

Stored in the cloud using SkyDrive

Roams with ApplicationData

Creating a configure once, use everywhere experience

Let’s get started with a simple configure once, use anywhere experience. Suppose I have an app that is a simple RSS reader that allows the user to read items from a set of feeds. When viewing a particular feed the app displays a certain number of items per page. I have a user configurable setting called ItemsPerPage that controls how many feed items to display on a page. I want to make it so if the user sets this setting on one PC, it will roam to other PCs that have my app installed. Within the ApplicationData class there is a RoamingSettings property, and enabling a setting to roam is as simple as writing it as a value in RoamingSettings.

JS:

Windows.Storage.ApplicationData.current.roamingSettings.values[“ItemsPerPage”] = 10

C#:

Windows.Storage.ApplicationData.Current.RoamingSettings.Values[“ItemsPerPage”] = 10;

That’s it! All the sync mechanics are handled by Windows, and that setting will now sync between all of the user’s PCs that have my app installed without any further action from me. This setting is typically presented to the user in the App Settings Charm. I highly recommend that you roam any app settings by default. Some settings may be machine specific and should not be saved into roaming locations.

If you wanted to write a file instead of a setting, Application Data also offers RoamingFolder, which functions the same way. If you choose to use a file for roaming data, be sure to close any open handles to the file when you are done writing to it. Files with open handles are not roamed.

Planning for the roaming quota

If all you use in your app are simple settings, then what we looked at so far is all you need. But what about a favorites list or a collection or larger amounts of data? How big can it be? Roaming app data is optimized for roaming settings and preferences and it does have a per-app storage quota that is suitable for these types of data. The quota exists to be considerate of system resources. Long battery life and system performance are important characteristics of Windows 8, and our limit helps ensure neither are sacrificed to deliver these roaming experiences. You can get this quota using ApplicationData’s RoamingStorageQuota property, which at the time of writing this is 100KB. The best way to work within the quota is to plan your app’s data usage at design time and ensure that it will not grow out of the quota.

So what happens if you exceed the RoamingStorageQuota? Nothing! More specifically, nothing roams. Your app will not break, and it can continue to read and write the data from the roaming locations. But until the total roaming data in the roaming locations is less than the RoamingStorageQuota, that data will not be synced to the cloud.

One common pitfall that we see with apps that don’t properly plan their roaming data usage is that they roam content instead of references to the content. For example, if I wanted to roam a set of favorite news articles I should roam the article identifiers or URLs, not the entire articles. Roaming raw data rather than references to available content is a fast way to burn through the quota and waste space. You can get the most out of roaming by roaming identifiers to content, not the actual content itself.

When planning your app it’s best not to use unwieldy sets of data. Any open-ended sets of data such as a favorites list should be capped so your app will always stay within the roaming quota. Continuing with my RSS feed reader example, suppose I wanted to save the list of RSS feeds, which is a user-managed list. The way to do this is to turn something that would otherwise be unbounded into something that has a limit. This requires a little estimation. Suppose I wanted to allocate 20KB for RSS feed lists. For simplicity I will give a conservative estimate of 80 bytes per URL. At that size I could cram 250 URLs into 20 KB. URL shortening could make this even smaller, but 250 is likely way more feeds than my app will ever need. All I have to do is cap it at that limit and write my feed list to a file, save it in the RoamingFolder, and it’s good to go.

Creating a continuous experience across PCs

There’s another cool roaming experience you can add to your app – the continuous user experience across PCs! Imagine a person at home on a desktop using my reader to catch up on their feeds who then needs to catch a bus. On the way out she grabs her Windows 8 tablet and opens up my app. The experience I want is for her to be able to continue reading right where she left on her desktop PC. Enabling the continuous experience is to preserve the context of what the user is doing and roam it.

Functionally this is no different than roaming any other setting, but this scenario is a bit different than most settings. The user may navigate through the feeds very rapidly, so this setting may change frequently while other settings typically don’t. Moreover, for the experience to really delight the user, the data needs to be accurate to what the user was last doing. To meet these customer needs we created a unique setting name that is specifically designed to handle this experience, HighPriority. To use it, simply name your setting HighPriority in the root container of the RoamingSettings. It is used like any other setting. The roaming engine allows this setting to roam much more quickly than other roaming data so you can deliver on that experience.

To enable this for my feed reader all I have to do is roam the feed identifier. On app launch or when resuming from suspend I check the identifier and navigate to the appropriate feed. It is very similar to my previous setting only the setting name is HighPriority.

JS:

Windows.Storage.ApplicationData.current.roamingSettings.values[“HighPriority”] = currentFeedId;

C#:

Windows.Storage.ApplicationData.Current.RoamingSettings.Values[“HighPriority”] = currentFeedId;

Like the other roaming experience, Windows takes care of all the hard stuff so you don’t need to worry about it. The key in using HighPriority is knowing when to read the setting and when to write it. Generally, check HighPriority on app launch or when it resumes after being suspended so the user can access whatever they were doing when last using the app, either on the current PC or another PC. We write HighPriority on user-initiated actions, like navigating to a new page or clicking on a link.

The HighPriority setting is often instantaneous but may be throttled with rapid writes, so unnecessary writes will only cause performance degradation within the app and not improve the roaming experiences. As a general rule, make HighPriority represent where and what the user is doing, such as when the user navigates to pages within the app or browses content. Some apps may have rapidly changing data, such as a video player that is keeping track of the counter within the video being played. It would be overkill to write to HighPriority every time the video counter increments, so instead you could update it when the video changes states such as play/pause, the user reaches a checkpoint, or when the app is suspended.

Keeping your data consistent

Some data is tightly coupled and should always roam together. The classic example is the coordinates for a point. You don’t want the x and the y coordinates roaming independently when changed or it can corrupt the data and create invalid points. The units of roaming for ApplicationData are settings and files, so anything within a file will always roam together as a unit, and a setting itself is a unit. If you want to roam multiple settings together, such as the coordinates, you can use a CompositeSettingValue. This type of setting allows grouping of multiple settings into a single value that will always roam as a unit.

The HighPriority setting can also be a composite, allowing you to safely roam multiple pieces of data that represent the current state of your app. For example, my feed reader groups feed items by pages for easy reading. I don’t want the feed ID and the page to ever roam independently of one another because the feeds may have different numbers of pages. What I really want to do is roam the current feed ID and the current page within that feed together as a CompositeSettingValue so they are always consistent.

JS:

var currentFeed = new Windows.Storage.ApplicationDataCompositeValue();
currentFeed.insert(“CurrentFeedId”, currentFeedId);
currentFeed.insert(“CurrentFeedPage”, currentFeedPage);
Windows.Storage.ApplicationData.current.roamingSettings.values[“HighPriority”] = currentFeed;

C#:

Windows.Storage.ApplicationDataCompositeValue currentFeed = 
new Windows.Storage.ApplicationDataCompositeValue();
currentFeed.Insert(“CurrentFeedId”, currentFeedId);
currentFeed.Insert(“CurrentFeedPage”, currentFeedPage);
Windows.Storage.ApplicationData.Current.RoamingSettings.Values[“HighPriority”] = currentFeed;

If a composite is used as the HighPriority setting then it must be under 8KB in order to retain the HighPriority benefits. Exceeding 8KB will not cause errors, but it will be roamed as if it were a normal setting.

Responding to incoming roaming changes

There is one last part of the roaming experience that you should know about, and that is ApplicationData’s DataChanged event. The DataChanged event is simply an event that you can signal whenever app data changes, such as signaling to a background task that the user changed a setting. When roaming data in the cloud causes a local change to your app, Windows will automatically signal this event for you. This allows you to respond to situations where data from another PC may have been delayed and then arrived after the user had already started using your app. You could use this event to refresh your view on the data or respond to setting changes. It is important to understand that this experience is optimized for consumers who use one PC at a time and switch between them, so you should not use DataChanged events as a real-time communication mechanism across PCs.

Become part of the connected experience

Having apps that utilize roaming is an important part of creating a connected Windows 8, and we’ve created a platform that makes it easy to create these cool new experiences. Roaming to the cloud is a great way for your app to stand out and delight your customers with convenience and a fluid transition between PCs. For additional guidance on using Roaming, please see the Guidelines for roaming application data. Also be sure to check out the ApplicationData sample, which contains examples of all of the experiences discussed in this blog entry. Thanks for reading!

-- Dave Bennett, Program Manager, Windows