The user experience for roaming app data is similar to a magic trick. Work is done behind the scenes to create the illusion that data is moving from place to place when, in fact, all that really happens is data gets copied and destroyed, over and over. The data itself never actually roams. Nevertheless, the user is made to feel that the same data is being teleported between the apps on his various devices instantaneously.
Have you ever noticed that getting roaming app data to sync between devices is a lot like transporting people through space on Star Trek? For instance, does anything actually get transported when crew members are sent through the transporter? Their pattern—a snapshot of the geometrical relationship between all of their atoms—is captured and then recreated using atoms at the destination. Since this creates duplicate data, though, the source version must be dematerialized—otherwise you end up with inconsistent versions of the same crew member.
In our previous post, we talked about what roaming data is, how to add it to your app and handle versions of the data, and how to test effectively. In today’s post, we’ll look at special considerations you can take to preserve the user experience:
- Roaming prerequisites
- First time data load
- Writing data
- Syncing and app suspension/termination
- Offline data
- Roaming data change notifications
Although you app will manage the sync of roaming data automatically in most cases, remember that just as with Star Trek transporters, a bit of engineering knowledge upfront can prevent awkward good Kirk/bad Kirk situations later.
A Microsoft account is the key to roaming app data. When users sign into a device with a Microsoft account and then open your app, Windows 10 knows to sync their roaming data in order to create the sense that their app data follows them around wherever they go. Without a Microsoft account, roaming data wouldn’t work. It is the unique signature that lets the vast Windows 10 roaming data system know where in the universe to transport your data.
Bear in mind that users or group policy administrators can switch off roaming app data on a device at any time. People can still use your app if roaming data is disabled, but their data won’t roam.
First time load and uninstalls
Windows handles a great deal of the workload associated with the first time load of app data. When an app is installed, the system assigns the app its own per-user data stores for settings and files. You don’t need to know where or how this data exists—Windows handles it. Windows also preserves or removes the contents of these data stores when users install updates or uninstall the app on their devices.
If an app is uninstalled from all devices belonging to a user, roaming data for that app will be preserved in the cloud for a reasonable amount of time—like the way Scotty was preserved in the transporter pattern buffer for 75 years when his ship crashed into a Dyson sphere. Roaming app data, however, will typically only be kept for a few weeks if the app isn’t reinstalled.
Handling synchronization during runtime is by far one of the most important aspects of roaming app data because it can have a big impact on user experience. The goal is to avoid performing any operation or task that could get in the way of the user experience.
How often should you sync your roaming app data? In general, this depends on whether the data changes frequently or only infrequently. For app data that changes infrequently, you can request a data sync whenever the data is updated. If your app data tends to change more frequently, it makes sense to sync periodically every five minutes or so. This not only saves on resources, but it also limits the number of times you need to save roaming app data to the cloud, potentially disrupting the user experience.
For example, in a music app you might write the “current song” settings whenever a new song starts to play. The actual position in the song, however, is something you would probably only want to write on suspend (as described below).
App suspension or termination
At some point, your app will be suspended, terminated, or both. Think about what should happen when your app enters these states to give your users have a more seamless roaming experience.
- Termination occurs when the user closes the app or the OS determines that the current loaded apps are using too many resources, even if they are in a suspended state
- Suspension occurs when a user switches to another app or minimizes an app
So what should happen when a user tries to switch back to a terminated app? Unfortunately, if you don’t do a little extra coding, it might appear to the user as if she has lost both her place in the app as well as all her information from the latest session—a bit like Thomas Riker must have felt when he got left behind on an uninhabited planet due to a freak transporter accident while his duplicate, William Riker, went on to have the Starfleet career he was meant to have. Not the best user experience!
You can keep this from happening by handling the Application.Suspending event. Then, override the Application.OnLaunched method when the app starts up again. The coding pattern for managing potential app termination only requires you to save off any useful data from the current user session. Then, if the app does get terminated, you can restore this data with custom code once the app is relaunched by the user.
And what about in a simple case of suspension? When the user switches away, the Application.Suspending event will fire. And when the user comes back a short time later, the Application.Resuming event will fire. This provides a seamless (and happy) experience for your user.
Dealing with offline users’ app data
Some users may occasionally run your app while offline, either because of a slow connection or no connection at all. When it comes to synchronization of offline data, there are two critical things to keep in mind:
- Avoid using roaming for data that relies on instant syncing.
- Understand that the last one written wins.
When a user goes offline, his or her data will be stored locally until connectivity is reestablished. Once the user is connected again, the OS (not you) will determine when to sync it up. For this reason, you’ll want to avoid using roaming for data that relies on instant syncing. You’ll also want to ensure that your UI itself does not depend on instant syncing—it could result in a UI with bad data or incorrect display.
During offline use, the possibility for sync conflicts also increases. Roaming app data is not intended for simultaneous use on more than one device at a time. If a conflict arises during synchronization because a particular data unit was changed on two devices, the system will always favor the value that was written last. This policy ensures the app utilizes the most-up-to-date information. This also ensures that transporter pattern merges like the splicing of Tuvok and Neelix into Tuvix on Star Trek Voyager can never actually occur.
Controlling the size of data
As we noted in the first blog in this series, the storage constraints on roaming app data (100 KB) mean that your app may stop synchronizing altogether if your roaming app data gets too large. And once an app stops synchronizing, the user experience suffers.
There are a few things you can do to keep your roaming app data as small as possible.
First, when you design your app, consider how to put a bound on larger data so as to not exceed the maximum storage. For example, if saving a game state requires 10 KB each time, You should limit the user to storing less than 10 games. At the same time, you should also look at how to make each game state save smaller if you can. Anything you can do to lower the total size of your roaming app data is important for the user experience.
Second, as a general rule, try to limit the use of roaming to data such as user preferences and customizations, links, and small data files. App data like a user’s background color preference, tasks, or the contents of a drafted email are all types of app data you can roam with relatively low storage demands.
Finally, remember to roam references to content rather than raw data. For example, roam a URL rather than the content of an online article.
If in doubt about how much storage is available, you can use the ApplicationData.RoamingStorageQuota property to find out. You can also use this to let your users see the size of their files and settings data to determine if they need to remove anything. This is a great way to encourage your users to help you keep their roaming app data small enough to keep syncing.
If you don’t wish to involve the user, you can proactively determine the total storage currently used to determine whether to allow or disallow the user to add a document or new setting as part of roaming app data.
The following code sample gets the current storage quota for a given device. It uses a method DisplayQuota() to render the current quota to the user. As you can see below, the API is very simple:
Here is a sample screenshot of running the code:
Roaming data change notifications
Even though roaming app data is not intended for simultaneous use on multiple devices, this can sometimes occur, so you must understand how to deal with this scenario. When the same app runs on two devices at the same time, the state of your roaming app data on these two devices may grow further and further apart over time.
While each version of the app is constantly overwriting the other version of the roaming app data kept in the cloud, neither device is necessarily being updated with these changes. They are writing but they may not be reading the roaming app data. With enough time, the app on each device will start resembling mirror universes of one another, with the differences becoming greater and greater—just like that Star Trek episode Mirror, Mirror where Spock in the evil universe has grown a Van Dyke while Spock in the good universe is clean shaven.
You can avoid situations like this by handling the ApplicationData.DataChanged event. This event will let your app know if the roaming data has been changed from another device. You can then manually reconcile the remote data with your local instance of the app in order to prevent confusing sync conflicts, as shown in this code sample.
this.Suspending += OnSuspending;
Windows.Storage.ApplicationData.Current.DataChanged += Roaming_DataChanged;
private void Roaming_DataChanged(Windows.Storage.ApplicationData sender, object args)
//manually sync local data with roaming data changes
In this series, we have hit all the high notes of roaming app data—from what it is and how it operates to some practical considerations for its use–to help you create seamless experiences for your users as they transition with your app from one device to the next throughout their day. By understanding how roaming app data works, you can help ensure that wherever your users materialize in the universe, their roaming app data will be able to find them.