Click here to Skip to main content
15,888,579 members
Articles / Programming Languages / C#

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

Rate me:
Please Sign up or sign in to vote.
4.89/5 (15 votes)
4 Apr 2018CPOL3 min read 66.7K   11   5
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 at least 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 Agent, We Need to Keep These in Mind

  • 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 tasks that we should remain careful about:

  1. Unsupported API
    • Some set of API cannot 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 Required Every Two week
    • Use ExpirationTime property of ScheduledTask object to set the time after which the task no longer runs.
    • 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 Crash
    • If the application has two consecutive crashes, 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 steps given below:

    Image 1

    Image 2

    Image 3

    Image 4

  2. In solution explorer, double click on ScheduledAgent.cs and add the following namespaces:
    C#
    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.
    C#
            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.
    XML
    <stackpanel>
        <stackpanel margin="0,0,0,40" name="PeriodicStackPanel" orientation="Vertical">
            <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 checked="PeriodicCheckBox_Checked"
                          ischecked="{Binding IsEnabled}"
                name="PeriodicCheckBox" 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 the following code:
    C#
                    #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 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 ensures that the agent will run after every one minute in debugging mode.
  9. In App.xaml.cs, add the following just after public static PhoneApplicationFrame RootFrame { get; private set; }:
    C#
    private static PeriodicTaskConfigure _periodicTaskConfigure;
    public static PeriodicTaskConfigure periodicTaskConfigure 
    {
        get
        {
          return _periodicTaskConfigure;
        }
    }
  10. Add:
    C#
    _periodicTaskConfigure = new PeriodicTaskConfigure();

    in App() after if(Debugger.IsAttached){}.

  11. In MainPage.xaml in the constructor, add:
    C#
    this.DataContext = App.periodicTaskConfigure;
    
  12. Add the following after Constructor in MainPage.xaml to call the methods of PeriodicTaskConfigure.cs:
    C#
    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

Image 5

Image 6

License

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


Written By
Software Developer Brainstation-23
Bangladesh Bangladesh
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionScheduled Interval Pin
MohamedZanoon15-Apr-14 0:57
MohamedZanoon15-Apr-14 0:57 
QuestionHow to download this Article / Example ? Pin
pardeep sharma921-Mar-14 23:35
pardeep sharma921-Mar-14 23:35 
GeneralMy vote of 5 Pin
Monjurul Habib22-Sep-13 3:54
professionalMonjurul Habib22-Sep-13 3:54 
good start! Welcome to CP Jubair. Hope we will get more from you. carry on Thumbs Up | :thumbsup:
GeneralMy vote of 5 Pin
ridoy21-Sep-13 23:25
professionalridoy21-Sep-13 23:25 
GeneralMy vote of 5 Pin
Mushfiq Shishir21-Sep-13 19:47
Mushfiq Shishir21-Sep-13 19:47 

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

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