- Web and HTTP
- HomeGroup
- Connectivity and Data Plans
- Sockets
- Proximity (Near Field Communications)
- Background Transfers
- Summary
Background Transfers
Many apps must download large amounts of information to present to the user. For example, an app focused on providing instructional videos might need to download new videos from the Internet. These files could be hundreds of megabytes or even gigabytes in size. Although the HttpClient class is capable of retrieving files of this size, you must also take into account the application lifecycle.
As you learned in Chapter 2, “Windows Store Apps and WinRT Components,” whenever the user moves your app into the background, your app can be suspended or frozen, essentially stopping any downloads dead in their tracks. In some scenarios, the app might even be terminated, forcing you to create a new instance of the class in an attempt to start the download again. Fortunately, WinRT provides a way to handle this specific scenario using a background task.
You learn more about background tasks in Chapter 15. This chapter introduces a specific API for downloading files that exists in the Windows.Networking.BackgroundTransfer namespace. The API is defined for several reasons. The most obvious is to enable your app to download files without interruption. These download tasks should continue even if your app is swapped to the background or terminated. You should also be able to discover any existing downloads when your app is launched again, to either continue to download or cancel them as needed. The extra advantage this API provides is a power-friendly and cost-aware means of transferring files. The API is architected to handle the download in a way that maximizes battery life and can pause the transfer when the user switches to a metered network. These features combine to provide the best mobile experience possible for the device user.
The reference project TapAndGoProximityNetworking serves two purposes. As a follow-up to the previous section about the Proximity API, it downloads an excellent video presentation by my colleague Jeff Prosise from Microsoft’s Channel 9 website. His talk, given at TechEd Europe in 2013, covers the Proximity API and provides working examples of encoding tags, reading tags, and tapping to share data between multiple devices. It is a great way to reinforce the information you learned in the previous section. The project downloads a high-fidelity version of the video that is almost 600MB in size. The second purpose is to demonstrate the background transfer capabilities.
To simplify the example, I placed all the code in the code-behind of the main page to simply download a file and then play it using the file launcher. The associated video player should pick up the file and begin playing the presentation after it is downloaded. The app first checks to see whether the movie already exists, based on a specific name in your video library. The Video Library capability must be enabled in the manifest for this to work. If the video exists, you are given the option to delete it to start over or launch it.
To start a background transfer, you need only two pieces of information: the URI of the resource to download and a file to download it to. The example app encodes the URI to the video download and creates a file with the name TapAndGo_Prosise.mp4 in your video library in the DownloadOnClick method.
var source = new Uri(DownloadUri, UriKind.Absolute); var destinationFile = await KnownFolders.VideosLibrary.CreateFileAsync( LocalName, CreationCollisionOption.ReplaceExisting);
An instance of the BackgroundDownloader class is created, and the CreateDownload method is called with the source and destination.
var downloader = new BackgroundDownloader(); download = downloader.CreateDownload(source, destinationFile);
You can provide a callback to receive updates as the download progresses. This is done by creating an instance of the Progress class of type DownloadOperation and passing the callback handler, as shown in the DownloadProgressAsync method.
var progress = new Progress<DownloadOperation>(UpdateProgress);
The download is then kicked off and cast to a Task with a cancellation token and the callback for progress.
await this.download.StartAsync().AsTask(cts.Token, progress);
The download is now kicked off and continues to execute even after your app terminates. If it encounters an error, it updates the error state for your app to query when the app is launched again. While the app is running, it provides progress updates, as shown in the UpdateFromProgress method.
BytesReceived.Text = download.Progress.BytesReceived.ToString(); TotalBytes.Text = download.Progress.TotalBytesToReceive.ToString();
Table 10.3 lists the possible statuses available via the Progress.Status enumeration. Use this to determine the state of the download and take appropriate action (in the example app, it is used to enable or disable the Pause and Resume buttons).
TABLE 10.3 BackgroundTransferStatus Enumeration
Status |
Description |
Idle |
The application is idle (the download is still active). |
Running |
The transfer is in progress. |
PausedByApplication |
The app has paused the download by calling the Pause method on the DownloadOperation. |
PausedCostedNetwork |
The user transitioned to a metered network, and the download has been paused to avoid additional cost. It will resume when the user returns to a nonmetered network. |
PausedNoNetwork |
The user has lost network connectivity. The download will resume when Internet connectivity is restored. |
Completed |
The operation successfully completed. |
Canceled |
The operation was canceled. |
Error |
An error was encountered. |
While the download is running, you can perform a number of actions. For example, you can call the Pause method on the DownloadOperation to temporarily pause the download. After it is paused, you can call Resume to continue the download. Calling Pause twice in a row or calling Resume before Pause results in an exception, so always keep track of or check the current status. If you passed a cancellation token to the task, you can also call Cancel on the token source to abort the download.
If the download completes while your app is still running, it returns control after await of the StartAsync call. The example app disposes of the cancellation token and then launches the video. If your app is terminated or exits before the download is finished, it will continue in the background. When the app is launched again, you can check for existing transfers, as the CheckState method shows.
var downloads = await BackgroundDownloader .GetCurrentDownloadsAsync();
An entry for the download exists whether it is still downloading or it completed when your app was not running. Either way, you can obtain the reference to the download, query the status, or attach to receive updates. The sample app always reattaches to update the status. If the download has completed, the call to AttachAsync returns immediately; otherwise, it continues the same way the call to StartAsync worked.
await this.download.AttachAsync().AsTask(cts.Token, progress);
To test the app, compile, deploy, and run it. Tap the Download button. You then see a status similar to Figure 10.4. You can pause, resume, or cancel the download. After the download has begun, close the app by stopping it if you are running through the debugger or by pressing Alt+F4. You can navigate to the video library and refresh the file list to verify that the download is still running. Start the app again; it should return to the progress display and begin showing you the current progress. If you let the download finish, the app automatically launches the video and closes itself.
FIGURE 10.4 The download progress
The transfer API enables you to launch multiple downloads and keep track of each download individually. You can also group downloads and perform various tasks on the group. In addition, you can set a priority for the download and even request that the download run unconstrained so that it happens more quickly. This prompts the user and also can affect battery life and quality of the user experience. You learn more about the various background APIs in Chapter 15.