Mobile Zone is brought to you in partnership with:

Den is a DZone Zone Leader and has posted 460 posts at DZone. You can read more from them at their website. View Full User Profile

Windows Phone Apps - Watch Your Code for Hidden Activity

03.26.2013
| 3574 views |
  • submit to reddit

How many apps have you released in the past year? How many of those did you thoroughly test, A to Z? How many of those did you try breaking with the good ol' "I have no idea what I'm doing" method? If you haven't then you should add that to your next testing routine, and here's why.

Let's take a piece of code as an example, and for that I am going to refer to Jonas Follesø's sample for QR code scanning on Windows Phone. It is a great sample and does the job right, but it might cause some problems if you move away from the demonstrated one-page application and have the scanner in a secondary page that is invoked from the main one. I've experienced this first hand when I was adapting the sample for one of my experimental applications.

To get an understanding of what's going on, let's start with the page constructor:

public MainPage()
        {            
            InitializeComponent();
 
            _matches = new ObservableCollection<string>();
            _matchesList.ItemsSource = _matches;
 
            _timer = new DispatcherTimer();
            _timer.Interval = TimeSpan.FromMilliseconds(250);
            _timer.Tick += (o, arg) => ScanPreviewBuffer();
        }

At this point it doesn't seem like anything is wrong - you have an associated handler for the pretty common Tick event, that is being called through a DispatcherTimer instance. Now let's take a look at what happens when the user navigates to this page:

protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            _photoCamera = new PhotoCamera();
            _photoCamera.Initialized += OnPhotoCameraInitialized;            
            _previewVideo.SetSource(_photoCamera);
 
            CameraButtons.ShutterKeyHalfPressed += (o, arg) => _photoCamera.Focus();
 
            base.OnNavigatedTo(e);
        }

Nothing out of the ordinary, but there is a camera initialization event hook. Subsequently, that event triggers, among other things, this:

 Dispatcher.BeginInvoke(() => {
                _previewTransform.Rotation = _photoCamera.Orientation;
                _timer.Start();
            });

Obviously, when the timer starts, so will the camera image processing through the above-mentioned Tick event handler. At this point, there is a tricky situation present with the given application workflow - try pinpointing it without actually using the code in an app.

Again - think in the context of a scenario where the page with the code shown above is not the only one used in the application. Let me save you the time and show the problem. Think of a possibility where the user navigated to the capture page, and then all of a sudden decided to navigate away by pressing the back button. 

The photo capture frame has already been pushed for initialization, therefore the app will ready for the OnPhotoCameraInitialized handler to be called, even if the user navigated away. What happens afterwards can potentially cause troubles, specifically - the timer will be started when there is no need for it, and it will be active in the background. Depending on how resource-intensive the underlying operation is, this might have an impact on the general performance. 

This issue can be mitigated in many ways - disposing of the timer object when the user navigates away (requires a follow-up null check to see whether a timer can be started) or having the PhotoCamera instance handled outside the page itself, which might not be as convenient to manage. As a general tip, in tasks that might be executed in the background, use the Output window as a notification hub for each iteration of the task, showing you that something is still going on.

The dangers of the situation from above are pretty clear - the code that will run in the background might not throw any visible indicators of its activity, but consume unnecessary memory and CPU cycles. When a user navigates away from a page, do not assume that everything that was going on in that page will automatically be destroyed. Be careful with background operations as well - a DispatcherTimer works outside the boundaries of a single page, therefore it needs to be stopped even if the page where it was invoked is not active in the application frame.