Quantcast
Channel: Envato Tuts+ Code - Mobile Development
Viewing all articles
Browse latest Browse all 1836

Windows Phone 8 Succinctly: Core Concepts

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-23261

In this tutorial, we'll cover some of the core concepts of Windows Phone development, such as asynchronous programming, navigation, and managing orientation changes. We'll also take a quick look at the life cycle of a typical Windows Phone application.

Asynchronous Programming

Nowadays, asynchronous programming is a required skill for developers. In the past, most applications worked with a synchronous approach: the user started an operation and, until it was completed, the application was frozen and completely unusable.

This behavior isn’t acceptable today, especially in the mobile world. Users wouldn’t buy a phone that doesn’t allow them to answer a call because an application is stuck trying to complete an operation.

There are two approaches in Windows Phone to manage asynchronous programming: callbacks and the async/await pattern.

Callbacks

In most cases, especially in Windows Phone 8, callbacks have been replaced with asynchronous methods that use the async and await pattern. However, there are some APIs that still use the callback approach, so it’s important to learn it.

Callbacks are delegate methods that are called when an asynchronous operation is terminated. This means that the code that triggers the operation and the code that manages the result are stored in two different methods.

Let’s look at the following example of the WebClient class, one of the basic APIs of the framework that performs network operations like downloading and uploading files:

The file download (in this case, we’re downloading the HTML of a webpage) is started when we call the DownloadStringAsync() method, but we need to subscribe to the DownloadStringCompleted event, which is triggered when the download is complete, to manage the result. Usually, the event handler (the callback method) has a parameter that contains the result of the request. In the previous sample, it’s called e and its type is DownloadStringCompletedEventArgs.

Notice the message “Download has started” that is written in the Visual Studio Output window. Since the method is asynchronous, the message will be displayed immediately after the download has started since the code will continue to run until the download is completed. Then, the execution moves to the callback method.

Async and Await

The callback approach is hard to read. Unlike synchronous code, the flow of execution “jumps” from one method to another, so a developer can’t simply read line after line to understand what’s going on. In addition, if you need to write a custom method that starts a network operation and returns the downloaded file, you simply can’t do it because the logic is split in two different pieces.

The async and await pattern was introduced in C# 5.0 to resolve these issues. The Windows Runtime is heavily based on this approach and most of the APIs we’re going to see in this series use it.

When we use the async and await keywords, we’re going to write sequential code as if it’s synchronous—the compiler will execute one row after the other. To better understand what happens under the hood, keep in mind that when we start an asynchronous operation, the compiler sets a bookmark and then quits the method. This way, the UI thread is free and users can keep interacting with the application. When the asynchronous operation is completed, the compiler goes back to the bookmark and continues the execution.

The async and await pattern is based on the Task class, which is the base return type of an asynchronous method. A method can return:

  • Task if it’s a void method: The compiler should wait for the operation to be completed to execute the next line, but it doesn’t expect a value back.
  • Task<T> if the method returns a value. The compiler will wait for the operation to be completed and will return the result (whose type is T) to the main method, which will be able to perform additional operations on it.

Let’s see an example. We’re going to add to our project a library called Async for .NET, which has been developed by Microsoft and is available on NuGet. Its purpose is to add async and await support to old technologies that don’t support it since they’re not based on C# 5.0, like Windows Phone 7 or Silverlight. It’s also useful in Windows Phone 8 applications, since it adds asynchronous methods to APIs that are still based on the callback pattern.

One of these APIs is the WebClient class we’ve previously seen. By installing this library we can use the DownloadStringTaskAsync() method which supports the new pattern. This method’s return type is Task<string>. This means that the operation is asynchronous and it will return a string.

First, let’s note how to use this new syntax. Any method that contains an asynchronous method has to be marked with the async keyword. In this case, it’s an event handler that is invoked when the user presses a button.

Next, we need to add the await keyword as a prefix of the asynchronous method. In our example, we’ve placed it before the method DownloadStringTaskAsync(). This keyword tells the compiler to wait until the method is completed before moving on.

When the asynchronous method is started, you can assume that the compiler has set a bookmark and then quit the method because the application is still responsive. When the download is completed, the compiler returns to the bookmark and continues the execution. The download’s result is stored in the result variable, whose value is displayed on the screen using a MessageBox.

As you can see, even if the code under the hood is asynchronous and doesn’t freeze the UI, it appears synchronous: the code is executed one line at a time and the MessageBox isn’t displayed until the DownloadStringTaskAsync() method has finished its job.

The Dispatcher

Sometimes, especially when you have to deal with callback methods, the operations are executed in a background thread, which is different from the thread that manages the UI. This approach is very helpful in keeping the UI thread as free as possible so that the interface is always fast and responsive.

Sometimes a background thread may need to interact with the user interface. For example, let’s say a background thread has completed its job and needs to display the result in a TextBlock control placed in the page. If you try to do it, an UnauthorizedAccessException error with the message “Invalid cross-thread access”will be displayed.

The reason for this error is that a background thread isn’t allowed to access the controls in a page since they are managed by a different thread. The solution is to use a framework’s Dispatcher class. Its purpose is to dispatch operations to the UI thread from another thread. This way, you can interact with XAML controls without issues because the thread is the same. The following sample illustrates how to use it:

You simply have to pass the Action that needs to be executed on the UI thread as a parameter of the BeginInvoke() method of the Dispatcher class. In the previous sample, the Action is defined using an anonymous method.

Tip: Anonymous methods are called such because they don’t have a specific name—they simply define the operations to be performed.

Dispatcher is not needed when you work with the async and await pattern because it makes sure that even if the operation is executed in one of the free threads available in the thread pool, the result is always returned in the UI thread.

Navigation

Another important concept to learn when you develop a Windows Phone application is navigation. In most cases, your application will be made of different pages, so you need a way to move from one page to another.

The framework offers a built-in navigation system, which can be managed using the NavigationService class.

The navigation system provides, in every page, two events that can be managed to intercept the navigation events: OnNavigatedTo() is triggered when you move from another page to the current page; OnNavigateFrom() is triggered when you move from the current page to another page. Another important page event that can be subscribed is Loaded, which is triggered when the page is completely loaded. It’s commonly used to load the data that needs to be displayed on the page.

Passing Parameters to Another Page

A common requirement when dealing with navigation is to pass a parameter to another page, for example, a master/detail scenario where you select a list item in the master page and display its details in a new page.

The navigation framework offers a built-in way to pass simple parameters like strings and numbers that is inherited directly from the web world: query string parameters. They’re added directly to the URL of the page where you want to redirect the user, as shown in the following sample:

You’ll be able to retrieve the parameter in the landing page by using the OnNavigatedTo event and the NavigationContext class, as in the following sample:

The NavigationContext class offers a collection called QueryString, which contains all the available parameters. You’ll be able to get the value by using its key (which is the parameter’s name).

In some cases, simple parameters aren’t enough. Sometimes you need to pass complex objects to another page. The master/detail scenario is, also in this case, a good example. In many situations, to properly populate the detail page, you need access to the whole object that has been selected in the list. 

A good approach to this is to pass the detail page a plain parameter that can be used to identify the selected item, like a unique identifier. Then, in the OnNavigatedTo event handler of the detail page, load the item with the received identifier from your data collection (which can be a database or a remote service).

Manipulating the Navigation Stack

Every application has its own navigation stack, which is the list of pages that the user has moved through while using the application. Every time the user navigates to a new page, it’s added to the stack. When the user goes back, the last page from the stack is removed. When one page is left in the stack and the user presses the Back button, the application is closed.

The NavigationService class offers a few ways to manipulate the stack. In the beginning, there’s a specific property called BackStack which is a collection of all the pages in the stack. When we discuss Fast App Resume later in this article, we’ll see one of the available methods to manipulate the stack: RemoveBackEntry(), which removes the last page from the stack.

Another important method is GoBack(), which redirects the user to the previous page in the stack. Its purpose is to avoid creating circular navigation issues in your application. 

The image below illustrates an example of circular navigation and how to correct it. Let’s say that you have an application made by two pages, a main page and a settings page. You choose to use the Navigate() method of the NavigateService class for every navigation. The user navigates from the main page to the settings page, and again to the main page. 

The issue here is that every time you call the Navigate() method, you add a new page to the navigation stack. When the user is on the main page and presses the Back button, he or she expects to quit the app. Instead, the second time, the user will be redirected to the Settings page since the previous navigation added the page to the stack. 

The correct approach is to use the GoBack() method. Instead of adding a new page to the stack, this method simply redirects the user to the previous one. The result will be the same—the user, from the settings page, is taken back to the main page—but since there are no pages added to the stack, the application will behave as expected. If the user presses the Back button, the app will be closed.

Circular Navigation Top and Correct Navigation Bottom

Intercepting the Navigation: The UriMapper Class

Later in the series we’ll deal with different situations where the application is opened with a special Uri, such as using the Speech API or data sharing.

In these cases, we’re going to use a navigation feature called UriMapper, which is a class that can act as a middle man in every navigation operation. When the user navigates from one page to another (the starting page can be also be the phone’s Home screen), the class is able to intercept it and redirect the user to another page if needed.

To create a UriMapper-based class, simply add a new class to your project. It has to inherit from the UriMapperBase class. It will require you to implement the MapUri() method, which is invoked during navigation as shown in the following sample:

The MapUri() method takes in the source Uri and needs to return the new Uri to redirect the user. In the previous sample, we checked whether the source Uri contained a specific string (in this case, it’s one that belongs to the data sharing scenario we’ll see later in this series). In the affirmative case, we redirect the user to a specific page of the application that is able to manage the scenario; otherwise, we don’t change the navigation flow by returning the original Uri.

After you’ve created a UriMapper class, you’ll have to assign it to the UriMapper property of the RootFrame object that is declared in the App.xaml.cs file. You’ll have to expand the region called Phone application initialization (which is usually collapsed), and change the InitializePhoneApplication() method like in the following sample:

The Application Life Cycle

Mobile applications have a different life cycle than traditional desktop applications due to their different requirements, like power management and performance optimization. The traditional multitasking approach that you experience in Windows doesn’t fit well to the mobile experience: the necessary power would drain the battery very quickly. Plus, if you open too many applications, you can suffer severe performance issues that will degrade the user experience.

The following figure explains the life cycle Microsoft has introduced for Windows Phone applications to satisfy the required conditions:

Application Life Cycle

When an application is running, it can be suspended at any time. For example, the user can press the Start button or tap a notification to open another application. In this case, the application is “frozen” (the dormant state); it’s preserved in memory, but all the running threads and operations are stopped. In this status, the application is using system memory, but the CPU is free. This way, other applications can use the available resources without suffering performance issues.

When the user decides to go back to the application (by using the Back button or the task switcher), its instance is restored from memory and the previous threads and operations are restarted.

If users play with their device for a long time, too many applications may be opened and there won’t be enough memory left to keep other applications suspended. In this case, the operating system can start to “kill” longer-running applications to free some memory for the newly opened apps—the older apps are moved into a tombstoned state. To give users the same smooth experience as when apps are simply suspended, developers have the ability to save the state of the app when it is tombstoned and restore it later. When users open a tombstoned app, they will find the application in the exact previous state, as if it’s never been closed.

The tombstoning experience was the only one available in Windows Phone 7, but it often led to a bad user experience. Because the app was killed, the application always needed to start from scratch, causing longer loading times. In Windows Phone 7.5, Microsoft introduced the Fast Application Switching concept that has been translated into the current life cycle, where apps are put in a dormant state and are killed only if needed.

Based on this information, we can understand that applications aren’t able to run in the background—when an application is suspended, all of its running operations are canceled. Later in this series, we’ll look at available techniques for executing some operations even when the app is not running.

As a developer, you are not notified by the operating system when an application is tombstoned. This is why, in the schema shown above, you can see that the save state operation is made every time the application is suspended. You’ll always have to deal with it, since you won’t know in advance whether your app will be tombstoned.

Instead, the restore operation is made only if the application has been tombstoned. When the app is in a dormant state, the entire process is stored in memory, so there’s no data loss when the app is restored.

Since tombstoning isn’t deterministic, Visual Studio offers a way to test it. By default, applications are moved to the dormant state when suspended. You can change this behavior by right-clicking on your project and choosing Properties. In the Debug section you’ll find the Tombstone upon deactivation while debugging option. When it’s selected, applications will always be tombstoned when they’re suspended, so you can test that everything works fine and no data is lost in this scenario.

Controlling the Life Cycle

You can control the application life cycle thanks to the PhoneApplicationService class, which is declared in the App.xaml file as a lifetime object.

As you can see, the PhoneApplicationService class is registered to manage four different events that are available in the App.xaml.cs file:

  • Application_Launching is invoked when the app starts for the first time.
  • Application_Closing is invoked when the app is completely closed. It only happens when the user presses the Back button in the application’s main page.
  • Application_Activated is invoked when the app is resumed from a suspended state.
  • Application_Deactivated is invoked when the app is suspended.

Remember the “save state” and “restore state” operations in the previous figure? Usually, they’re managed in these events. State is saved when the Application_Deactivated event occurs, and it’s restored when the Application_Activated event occurs.

Specifically, one of the parameters of the Application_Activated event handler contains important information—it shows whether the application comes from a dormant or tombstoned state as demonstrated in the following sample:

The key is the IsApplicationInstancePreserved property of the ActivatedEventArgs object, which is a Boolean. If it’s true, the app was in a dormant state; otherwise, it was killed, and it’s time to restore the data we’ve previously saved.

The PhoneApplicationService class can also be useful to store the state of your application when it’s suspended. In fact, it offers a property called State that is a collection whose type is Dictionary<string, object>. It can be used to save any object that is identified by a key.

Typically, you’re going to save data in the State property when the app is suspended, and restore the data when the app is resumed from a tombstoned state.

However, there are some important things to keep in mind:

  • It’s best to save data as soon as possible and not only when the Application_Deactivated event is raised. Unexpected bugs or other errors can cause users to lose data during the execution.
  • The content of the State property is kept in memory only if the app is resumed; if the user decides to open the application from scratch (for example, by tapping on its Tile instead of using the Back button), the collection is erased and the saved data will be lost. If you need to persist the data across multiple executions, it’s better to save to the local storage, which we’ll cover later in this series.

Fast App Resume

The life cycle previously described has a flaw: users can resume a suspended application only by using the Back button or the task switcher. If they pin a Tile for the application on the Start screen and tap on it, a new instance of the app will be opened and the suspended one will be terminated.

Windows Phone 8 has introduced a new feature called Fast App Resume, which can be activated to address the flaw previously described. Regardless of the opening point, if there’s a suspended instance, it will always be used.

Supporting Fast App Resume requires a bit of work because, by default, the Windows Phone template is made to use the old life cycle, even when the feature is activated.

The first step is to modify the manifest file, and unfortunately, it’s one of the situations where the visual editor isn’t helpful. In fact, we’ll need to manually edit the file. To do this, simply right-click the WMAppManifest.xml file inside the Properties folder and choose the View code option.

You’ll find a node called DefaultTask that tells the application which page to load first when the app starts. You’ll need to add an attribute called ActivationPolicy to set its value to Resume, like the following sample:

What happens when users tap on the main Tile of the application and the Fast App Resume has been enabled? The operating system triggers two navigations: the first one is toward the last opened page in the application, and the second one is toward the main page of the application, since the application Tile is associated with it through the default navigation Uri.

At this point, you have two choices:

  • You can keep using the old approach. In this case, you have to remove the last visited page from the back stack; otherwise you’ll break the navigation system. In fact, when users are on the main page of the application and press the Back button, they expect to quit the application, not go back to an old page.
  • You can support Fast App Resume. In this case, you have to stop the navigation to the main application page so that users are taken to the last visited page of the application.

The default Windows Phone 8 templates contain an implementation of the first approach. Open the App.xaml.cs file and look for a method called InitializePhoneApplication(), which takes care of initializing the frame that manages the various pages and the navigation system. You’ll find that the application subscribes to an event called Navigated of the RootFrame class, which is triggered every time the user has moved from one page of the application to another.

The method that is assigned as the handler of this event is called ClearBackafterReset(), which has the following definition:

This method does exactly what was previously described: the navigation to the main page is not canceled but, using the RemoveBackEntry() method of the RootFrame class, the page stack of the application is cleaned.

Take note of the NavigationMode property: it specifies the status of the navigation, like New when users navigate to a new page, or Back when users go back to a previous page. The key status to manage Fast App Resume is Reset, which is set when users are navigating to the main application page but an old instance of the app is being used.

We’re going to use the NavigationMode property together with some changes to the original code. The first step is to change the Navigated event handler to simply store, in a global Boolean property of the App.xaml.cs class, whether the NavigationMode is reset. We’re going to use this information in another event handler. In fact, we need to subscribe to the Navigating event of the RootFrame class. This event is similar to the Navigated one, except that it is triggered before the navigation starts and not after. This difference is important for our purpose, since we have the chance to cancel the navigation operation before it’s executed.

Here is what we do in the Navigating event handler:

In this event, we wait for a specific condition to happen: the NavigationMode is Reset and navigation to the main page is triggered. This situation occurs when users tap on the main Tile and an instance of the app is already in memory. The first navigation redirects to the last visited page, and the second one (the Reset mode) redirects to the main page. It’s this scenario that we need to manage. By setting the Cancel property of the method’s parameter, we abort the navigation to the main page and leave the user on the last-visited page of the app. The experience is exactly the same as when the user returns to the application using the Back button.

Here is how the complete code required to implement Fast App Resume looks in the App.xaml.cs file:

You may be wondering why all this effort is needed to support Fast App Resume. Why isn’t it automatically implemented by the operating system? The answer is that Fast App Resume isn’t suitable for every application—you have to be very careful when you decide to support it, because you can ruin the user experience if you don’t implement it well.

For example, if your users spend most of the time in the main page of your application (for example, a social networking app), they probably prefer to go straight to the Home page when they open the application, instead of resuming what they were doing before.

Here are two tips for improving the Fast App Resume experience:

  • If your application has many pages and a complex navigation hierarchy, add to the inner pages a quick way to go back to the home page (like a button in the Application Bar).
  • Add a timing condition. If the application hasn’t been used recently, disable Fast App Resume and redirect the user to the home page.

Manage Orientation

Typically, a Windows Phone device is used in portrait mode, but there are some scenarios where users can benefit from landscape mode. For example, if your application offers a way to insert long text, it can be more convenient for users to type using the landscape keyboard. Alternatively, in other scenarios, you can use the landscape mode to provide the content with a different layout.

By default, every new page added to a Windows Phone is displayed in portrait mode and does not support the landscape mode. When you rotate the phone, nothing happens. The orientation behavior is controlled by two attributes of the PhoneApplicationPage node in the XAML:

  • The SupportedOrientations property defines which orientations are supported by the page. To support both orientations, you need to set the value to PortraitOrLandscape.
  • The Orientation property defines the default orientation of the page.

Once you’ve set the SupportedOrientations property to PortraitOrLandscape, the page’s layout will automatically adapt to landscape mode when the phone is rotated.

If you want further control (for example, because you want to deeply change the page’s layout between portrait and landscape modes), the APIs offer a page event called OrientationChanged that is raised every time the phone is rotated from portrait to landscape mode and vice versa. The event is exposed directly by the PhoneApplicationPage class, so you can subscribe it in the XAML, as in the following sample:

The event handler that will be generated in the code will return the information about the new orientation. You can use it to move or change the aspect of the controls placed in the page. The following sample shows how to set a different Height of a Button control, according to the detected orientation:

Conclusion

If you’re new to Windows Phone development, this article is very important, because we’ve learned some basic core concepts that we’re going to use again in later installments of this series.

Here is a quick recap:

  • Asynchronous programming is must-have knowledge for mobile developers. We’ve learned how callbacks and the new async and await pattern will help you keep the user interface fast and responsive.
  • It’s highly unlikely that your application is made of just one page, so we’ve learned how to support navigation between different pages and how to correctly manage the navigation flow.
  • Application life cycle is another key concept. You have to understand how a Windows Phone application works under the hood to correctly manage all the multitasking scenarios. We’ve talked about Fast Application Switching, an improvement introduced in Windows Phone 7.5 to make the suspending and resuming process faster, and Fast App Resume, a new Window Phone 8 feature that improves the resuming experience.

This tutorial represents a chapter from Windows Phone 8 Succinctly, a free eBook from the team at Syncfusion.

2015-03-05T20:41:29.000Z2015-03-05T20:41:29.000ZMatteo Pagani

Viewing all articles
Browse latest Browse all 1836

Trending Articles