吴佳鑫的个人专栏

当日事当日毕,没有任何借口

导航

修炼九阴真经Windows Phone开发 (11):计划任务PeriodicTask和ResourceIntensiveTask概述和示例

前面提到,

计划任务允许应用程序执行后台代理程序,执行条件是主程序未激活。与计划通知不同的是,计划任务只能选择两种类型执行,即 PeriodicTask 和 ResourceIntensiveTask.

PeriodicTask 定期执行,但是执行时间短,且限制使用处理周期和内存等系统资源。此类型适合快速任务,比如检查启用位置功能的WEB服务的用户数,或者缓冲小量数据。

ResourceIntensiveTask 不定期执行,在设备处于资源充沛的情况下执行,比如设备处于WIFI网络连接状态并且设备采用外接电源供电。此类型的任务在允许使用充足的设备资源时,可以运行更长的时间处理大量的数据,即此类型的任务执行时间是弹性的。

以下摘自MSDN。,

 

 

计划任务和后台代理都允许应用程序在后台执行代码,即使当应用程序未在前台运行时也是如此。不同类型的计划任务是针对不同类型的后台处理方案设计的,因此具有不同的行为和限制。本主题介绍计划任务的计划、持续时间和限制。

 

下面是计划任务的类型。请注意,ScheduledTask 派生自 ScheduledAction。在后台运行的代码放置在从 ScheduledTaskAgent(派生自 BackgroundAgent)派生的类中。

 

计划任务类型

说明

PeriodicTask

定期代理以定期重复的间隔运行一小段时间。这种类型的任务的典型方案包括上传设备的位置以及执行少量的数据同步。

ResourceIntensiveTask

资源密集型代理在手机符合与处理器活动、电源以及网络连接有关的一组要求时运行,运行的时间相对较长。这种类型任务的典型方案是,在用户没有主动使用手机时将大量数据同步到手机。

 

一个应用程序可能只有一个后台代理。可以将该代理注册为 PeriodicTaskResourceIntensiveTask 或两者。运行代理的计划取决于注册的任务类型。将在本主题的后面部分介绍计划的详细信息。一次只能运行代理的一个实例。

代理的代码由应用程序在从 BackgroundAgent 继承的类中实现。代理启动时,操作系统调用 OnInvoke(ScheduledTask)。在该方法中,应用程序可以确定它以哪种 ScheduledTask 类型运行,并执行相应的操作。代理完成其任务之后,它应该调用 NotifyComplete()()()()Abort()()()() 以让操作系统知道它已完成。如果任务成功,则应该使用 NotifyComplete。如果代理无法执行其任务(如所需的服务器不可用),则代理应该调用 Abort,这将导致 IsScheduled 属性设置为 false。前台应用程序可以在其运行时检查该属性,以确定是否调用了 Abort

 

以下限制适用于所有计划任务。

 

限制

说明

不支持的 API

有一组无法由任何计划任务使用的 API。使用这些 API 将导致在运行时引发异常,或者将导致在提交到 Windows Phone 商城 期间应用程序无法认证。有关受限制的 API 的列表,请参阅 Windows Phone 的后台代理不支持的 API

内存使用上限

定期代理和资源密集型代码任何时候都不能使用超过 6 MB 的内存。音频代理限制为 15 MB。如果计划任务超过此内存上限,则立即终止。

在调试器下运行时,暂停内存和超时限制。可以使用 ApplicationMemoryUsageLimit API 查询前台应用程序和后台代理的内存限制。

每隔两周需要重新计划

使用 ScheduledTask 对象的 ExpirationTime 属性设置之后不再运行任务的时间。当使用 Add(ScheduledAction) 方法计划操作时,该值必须设置为两周之内的某个时间。当与该任务关联的应用程序在前台运行时,可能会重新计划该任务并将过期时间重置为从当前时间起最多两周。

两次连续崩溃之后取消代理计划

如果由于超过内存配额或任何其他未处理的异常而连续两次退出,则取消定期代理和资源密集型代理的计划。代理必须由前台应用程序重新计划。

 

以下是定期代理的计划、持续时间和常规限制。

 

限制

说明

计划间隔:30 分钟

定期代理通常每隔 30 分钟运行一次。若要优化电池使用时间,定期代理的运行可以与其他后台进程一致,因此执行时间可能最多漂移 10 分钟。

计划持续时间:25 秒

定期代理通常运行 25 秒。其他限制可能会导致代理提取终止。

节电模式可能会阻止执行

节电模式是一个选项,用户可以在设备上启用该选项以指示应该优先考虑电池使用时间。如果启用此模式,则定期代理可能不运行,即使间隔已过也是如此。

每个设备的定期代理限制

为了帮助最大程度地提高设备的电池使用时间,对手机上可以计划的定期代理数量进行了硬性限制。它因每个设备配置而异并且可以低到 6。还有另一个低于硬性限制的限制,超过该限制之后会警告用户他们正在运行多个后台代理,因此电池消耗可能比较快。

警告说明警告:
当超出设备限制时,如果您尝试添加定期后台代理,则对 Add(ScheduledAction) 的调用将引发 InvalidOperationException。由于每个设备的定期代理限制非常低,因此您的应用程序很可能会遇到此异常。出于此原因,您在添加定期代理时捕获此异常非常重要,这样您的应用程序就不会崩溃。其示例代码可以在 Windows Phone 的后台代理最佳做法中找到。

 

以下是资源密集型代理的计划、持续时间和常规限制。

 

限制

说明

持续时间:10 分钟

资源密集型代理通常运行 10 分钟。其他限制可能会导致代理提取终止。

需要外部电源

除非设备连接到外部电源,否则不运行资源密集型代理。

需要非手机网络连接

除非设备通过 Wi-Fi 或 PC 连接建立网络连接,否则资源密集型代理不运行。

最低电池电量

除非设备的电池电量高于 90%,否则资源密集型代理不运行。

需要设备屏幕锁定

除非设备屏幕锁定,否则资源密集型代理不运行。

非活动手机呼叫

当手机呼叫处于活动状态时,资源密集型代理不运行。

不能将网络更改为手机网络

如果资源密集型代理尝试调用指定 MobileBroadbandGSM()()()()MobileBroadbandCDMA()()()()AssociateToNetworkInterface(Socket, NetworkInterfaceInfo),则该方法调用失败。

如果设备达到了一种状态,即,符合所有需要的条件并且启动了资源密集型代理,那么当设备状态发生更改以至于不符合任何条件时,则会立即终止资源密集型代理。

 ------------------------------------------------------------------------------------------------------

 在Wondwos Phone 7.1中,提供了可以进行多个工作计划任务的方法,我们可以定义一个工作内容之后,交由作业系统来执行这段程序,不过因为手机本身的资源限制,所以并不是所有的工作都可以执行。Windows Phone 7.1中支援二种可以在背景计划任务执行的工作:

  1、PeriodicTask

  2、ResourceIntensiveTask

  这二种工作执行的方式都有要求的条件:

  PeriodicTask:

  执行时间:每30分钟执行一次,误差可能约10分钟

  内存最大使用量:小于6 MB

  可执行时间:25秒。

  省电模式时可能不执行

  可执行上限数:6个。

 

 

  ResourceIntensiveTask:

  内存最大使用量:小于6 MB

  可执行时间:10分钟。

  执行条件:外接电源、需使用Wi-Fi或是直接连接电脑、电池电源需大于90%、营幕不可锁定、不在接电话的状态等。

  每个应用程式最多只能设定一个PeriodicTask 和 ResourceIntensiveTask,工作的到期日(ExpirationTime)必需在二周内,而且有部份API无法使用,要排定工作必须在使用者第一次执行的应用程式的时候,没办法在安装时就启动排程,使用上的限制还蛮多的。

 

 

 

示例一:

 

  建立计划任务的方式还蛮简单的,先建立一个基本的Windows Phone App,再建立计划任务的项目,App引用计划任务。

  

SNAGHTMLd7c6eb
 
接下来就是在App放一个button来启动工作排程啦:

  

image
 
 
 
 
 
 
 
 
       private void btnStart_Click(object sender, RoutedEventArgs e)  
         {  
             PeriodicTask task = (PeriodicTask)ScheduledActionService.Find("TaskAgent");  
             if (task == null)  
             {  
                 task = new PeriodicTask("TaskAgent");  
                 task.Description = "顯示目前時間";  
             }  
             else 
             {  
                 //沒在排程狀態  
                 if (!task.IsScheduled)  
                 {  
                     string lastResult;  
                     if (IsolatedStorageSettings.ApplicationSettings.TryGetValue<string>("taskResult", out lastResult))  
                     {  
                         if (lastResult == "Succes")  
                         {  
                             MessageBox.Show("使用者已關閉排程");  
                             ScheduledActionService.Remove(task.Name);  
                             return;  
                         }  
                         else if (lastResult == "Faillure")  
                         {  
                         }  
                     }  
                 }  
                 ScheduledActionService.Remove(task.Name);  
             }  
   
             //到期時間  
             task.ExpirationTime = DateTime.Now.AddDays(14);  
             try 
             {  
                 ScheduledActionService.Add(task);  
 #if DEBUG_AGENT  
                 ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(60));  
 #endif  
             }  
             catch (InvalidOperationException)  
             {  
                 MessageBox.Show("排程執行已達上限數或使用者停止相關功能。");  
             }  
             catch (SchedulerServiceException sse)  
             {  
                 MessageBox.Show(sse.Message);  
             }  
         } 

 

 

  把工作加入排程之前,记得先判断是否有重覆;如果已经有排程了,那就要判断目前排程执行的状况,若是需要重新排程,就把目前的排程先移除之后再重新加入。

  另外,测试时可以利用ScheduledActionService.LaunchForTest来达到快速执行(不然最少都要等30分鐘左右哦!)

        protected override void OnInvoke(ScheduledTask task)
        {
            if (task is PeriodicTask)
            {
                // Logic for Periodic Task
            }
            else
            {
                // Logic for ResourceIntensiveTask
            }
            // Use this to invoke your task much quicker when debugging
#if DEBUG_AGENT
            ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(60));
#endif
            // Tell the Scheduler we are done
            NotifyComplete();
        }
 
 
 
 

 

posted on 2012-04-30 17:52  _eagle  阅读(941)  评论(0编辑  收藏  举报