Click here to Skip to main content
Click here to Skip to main content

Windows Phone 8 Background Agent (Part 1: Periodic Task)

, 21 Sep 2013
Rate this:
Please Sign up or sign in to vote.
This article gives you a brief overview on Windows Phone 8 Background Agent and focuses on Periodic Task

Introduction

Scheduled tasks and background agents can run when the application is not running in the foreground. Windows Phone apps are in dormant state when running in the background or the phone is locked. This article assumes that you are good in MVVM design pattern or atleast you know how it works. It also assumes that you know about data binding in XAML

Types Of Background Agent

  • Periodic Task
  • Resource Intensive Task

When creating a background agents we need to keep these in minds

  • An application can have only one background agent. It can be periodic or resource intensive or can be both.
  • The schedule depends on which type of task it is registered.
  • Do not use critical logic at background agent because they may not run.

Constraints for all scheduled task (both Periodic and Resource Intensive)

There are some constraints for both periodic and resource intensive task that we should remain careful about

  1. Unsupported API
    • Some set of API can not be used by the scheduled task.
  2. Memory Usage Cap
    • Only 11 mb of memory can be used.
    • Audio agents can use up to 15 mb of memory
  3. Reschedule Require Every Two week
    • Use ExpirationTime property of ScheduledTask object to set the time after which the task no longer run
    • This value must be set within two weeks
    • If Background agent calls Update(ShellTileData) to update the tile, the expiration time is automatically extended to two weeks.
    • If application display notification in lock screen, the time will be automatically extended to two weeks whenever your background agent calls.
    • If your app auto-uploads photos using a resource-intensive agent, the resource-intensive agent schedule will not expire as long as the user has enabled this feature for your app in the photos+camera settings page
  4. Agent Unscheduled after two Consecutive crush
    • If the application has two consecutive crush, the background agent will be unscheduled

In this article I am going to focus on periodic task. My next article will describe the Resource Intensive task.


Periodic Agents

There are some fixed constraints for periodic agents. Before going to code we need to know about these constraints.

  1. Scheduled Interval
    • Typically run every 30 minutes
  2. Scheduled duration:
    • Periodic agents typically run for 25 seconds
  3. Battery Saver Mode:
    • If this mode on, periodic agents will not run.
  4. Per device periodic agent limit:
    • Only 6 periodic agents are allowed per device

Creating a Simple periodic agent Step by Step

  1. Follow the following steps




  2. In solution explorer double click on ScheduledAgent.cs and add following namespaces:
                    using Microsoft.Phone.Scheduler;
                    using Microsoft.Phone.Shell;
                    using System;
    
                
  3. Add the following code in OnInvoke() method in ScheduledAgent.cs. This method is called when Background agent is launched.
                    protected override void OnInvoke(ScheduledTask task)
            {
                string ToastMessage = string.Empty;
    
                if (task is PeriodicTask)
                {
                    ToastMessage = "Periodic task is running";
                }
                
    
                ShellToast Toast = new ShellToast();
                Toast.Title = "Background agent sample";
                Toast.Content = ToastMessage;
                Toast.Show();
                NotifyComplete();
    
                #if DEBUG_AGENT
                ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(60));
                #endif
            }
    
                
    • We want to send toast message with our background agent. So we create an object of ShellToast. NotifyComplete() is called to let the system know that the work is done by the agent.
    • With these lines, we tell that if we are in debugging mode the agent will run after every 60 seconds or 1 min. If we don’t use these lines we may need to wait for a long time to run the background agent when debugging.
  4. Next put the following code in MainPage.xaml in ContentPanel.
                    
                <stackpanel>
                    <stackpanel orientation="Vertical" name="PeriodicStackPanel" margin="0,0,0,40">
                        <textblock text="Periodic Agent">
                        <stackpanel orientation="Horizontal">
                            <textblock text="name: ">
                            <textblock text="{Binding Name}">
                        </textblock></textblock></stackpanel>
                        <stackpanel orientation="Horizontal">
                            <textblock text="is enabled" verticalalignment="Center">
                            <checkbox name="PeriodicCheckBox" ischecked="{Binding IsEnabled}" checked="PeriodicCheckBox_Checked" unchecked="PeriodicCheckBox_Unchecked">
                        </checkbox></textblock></stackpanel>
                        <stackpanel orientation="Horizontal">
                            <textblock text="is scheduled: ">
                            <textblock text="{Binding IsScheduled}">
                        </textblock></textblock></stackpanel>
                        <stackpanel orientation="Horizontal">
                            <textblock text="last scheduled time: ">
                            <textblock text="{Binding LastScheduledTime}">
                        </textblock></textblock></stackpanel>
                        <stackpanel orientation="Horizontal">
                            <textblock text="expiration time: ">
                            <textblock text="{Binding ExpirationTime}">
                        </textblock></textblock></stackpanel>
                        <stackpanel orientation="Horizontal">
                            <textblock text="last exit reason: ">
                            <textblock text="{Binding LastExitReason}">
                        </textblock></textblock></stackpanel>
                    </textblock></stackpanel>
                    
                </stackpanel>
                
  5. Right click on PhoneApp1 and add> New Folder.
  6. Name the Folder ViewModel
  7. Right click on ViewModel and click add> class.
  8. Name the class PeriodicTaskConfigure and add following code
                    #define DEBUG_AGENT
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Microsoft.Phone.Scheduler;
    
    namespace PhoneApp1.ViewModel
    {
        public class PeriodicTaskConfigure : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void OnPropertyChanged(string name)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null)
                {
                    handler(this, new PropertyChangedEventArgs(name));
                }
            }
    
    
            PeriodicTask periodicTask { get; set; }
    
    
            public string Name = "Periodic Agent";
    
            private bool? _isEnabled;
    
            public bool? IsEnabled
            {
                get { return _isEnabled; }
                set 
                { 
                    _isEnabled = value;
                    OnPropertyChanged("IsEnabled");
                }
            }
    
            private bool? _isScheduled;
    
            public bool? IsScheduled
            {
                get { return _isScheduled; }
                set 
                {
                    _isScheduled = value;
                    OnPropertyChanged("IsScheduled");
                }
            }
    
            private DateTime? _lastScheduledTime;
    
            public DateTime? LastScheduledTime
            {
                get { return _lastScheduledTime; }
                set 
                { 
                    _lastScheduledTime = value;
                    OnPropertyChanged("LastScheduledTime");
                }
            }
    
            private DateTime? _expirationTime;
    
            public DateTime? ExpirationTime
            {
                get { return _expirationTime; }
                set 
                { 
                    _expirationTime = value;
                    OnPropertyChanged("ExpirationTime");
                }
            }
    
            private string _LastExitReason;
    
            public string LastExitReason
            {
                get { return _LastExitReason; }
                set 
                { 
                    _LastExitReason = value;
                    OnPropertyChanged("LastExitReason");
                }
            }
    
            public void Page_Active()
            {
                periodicTask = ScheduledActionService.Find(Name) as PeriodicTask;
    
                if (periodicTask != null)
                {
                }
            }
    
            public void StartPeriodicAgent()
            {
               
                
                periodicTask = ScheduledActionService.Find(Name) as PeriodicTask;
    
                if (periodicTask != null)
                {
                    RemoveAgent();
                }
    
    
                periodicTask = new PeriodicTask(Name);
                periodicTask.Description = "this describes the periodic task";
    
                try
                {
                    ScheduledActionService.Add(periodicTask);
                    LoadPeriodicTaskData();
                    
                    #if(DEBUG_AGENT)
                    ScheduledActionService.LaunchForTest(Name, TimeSpan.FromSeconds(60));
                    #endif
                }
                catch (Exception e) { }
            }
    
            public void RemoveAgent()
            {
                try
                {
                    ScheduledActionService.Remove(Name);
                    EmptyPeriodicData();
                }
                catch (Exception e)
                {
                }
            }
    
            private void LoadPeriodicTaskData()
            {
                this.IsEnabled = periodicTask.IsEnabled;
                this.IsScheduled = periodicTask.IsScheduled;
                this.LastScheduledTime = periodicTask.LastScheduledTime;
                this.LastExitReason = periodicTask.LastExitReason.ToString();
                this.ExpirationTime = periodicTask.ExpirationTime;
            }
    
            private void EmptyPeriodicData()
            {
                this.IsEnabled = null;
                this.IsScheduled = null;
                this.LastScheduledTime = null;
                this.LastExitReason = null; ;
                this.ExpirationTime = null;
            }
           
    
        }
    }
    
                
    • In StartPeriodicAgent() method you first need to check if there is any agent is already registered. If there is any registered agent you need to remove it as an app can have only one background agent.
    • #define DEBUG_AGENT this ensure that the agent will run after every one minute in debugging mode.
  9. In App.xaml.cs add following just after public static PhoneApplicationFrame RootFrame { get; private set; }
    private static PeriodicTaskConfigure _periodicTaskConfigure;
    public static PeriodicTaskConfigure periodicTaskConfigure 
    {
        get
        {
          return _periodicTaskConfigure;
        }
    }
    
                
  10. Add
    _periodicTaskConfigure = new PeriodicTaskConfigure();
    in App() after if(Debugger.IsAttached){}
  11. In MainPage.xaml in the constructor add
     this.DataContext = App.periodicTaskConfigure;
  12. Add following after Constructor in MainPage.xaml to call the methods of PeriodicTaskConfigure.cs
            private void PeriodicCheckBox_Checked(object sender, RoutedEventArgs e)
            {
                App.periodicTaskConfigure.StartPeriodicAgent();
                
            }
    
            private void PeriodicCheckBox_Unchecked(object sender, RoutedEventArgs e)
            {
                App.periodicTaskConfigure.RemoveAgent();
            }
    
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                App.periodicTaskConfigure.Page_Active();
            }
                

Output



License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Abdullah Jubair
Student
Bangladesh Bangladesh
No Biography provided

Comments and Discussions

 
QuestionScheduled Interval [modified] PinmemberMohamedZanoon15-Apr-14 0:57 
QuestionHow to download this Article / Example ? Pinmemberpardeep sharma921-Mar-14 23:35 
GeneralMy vote of 5 PinmemberMonjurul Habib22-Sep-13 3:54 
GeneralMy vote of 5 Pinprofessionalridoy21-Sep-13 23:25 
GeneralMy vote of 5 PinmemberShiss21-Sep-13 19:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 22 Sep 2013
Article Copyright 2013 by Abdullah Jubair
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid