吴佳鑫的个人专栏

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

导航

修炼九阴真经Windows Phone开发 (12):计划任务Background Schedule Tasks总结及示例

在WP7.1中针对Background Agent的新API增加了蛮多非常强大的部分,以下将介绍Scheduled Multi Tasking的部分。

  Scheduled Multi Tasking主要是让Application支援多工模式来执行任务,让Application不在前景模式下也可以继续在背景执行某些特定的任务,例如:背景下载、背景更新资料、背景唿叫服务…等。

  然而,WP7.1提供Agent的模式,让开发Application时将要背景执行的逻辑,独立放置于Agent之中透过排程来完成任务。

  但要注意的是,Agent与Application必竟还是属于不同的专案,因为IsolatedStorage中的IsolatedStorageSettings无法共用,要交换资料需透过IsolatedStorage档案或其他方式来交换。

  因此,在设计一个支援Background Agent(ScheduledTaskAgent)的Application时,我个人会有几个考量:

  1. 将背景执行的逻辑独立成一个类别或模组,由该模组完成所有背景的任务;

  2. 使用设定档(config)的方式,将参数或执行结果独立于档案,提供Application与Agent均可以取得;

  3. Agent是背景的任务,在背景发生Exception的容错机制需要特别设计,尽量透过通知告知用户;

  接下来,将细部去讨论Scueduled Tasking由那些重要的元素组成:

  〉Microsoft.Phone.Scheduler - Scheduled Multi Tasking:

  WP7.1允许Schedule Task与Background Agent在背景执行它们的任务,然而Schedule Task与Background Agent使用上却有所不同:

  ‧Schedule Task:重点在于指定「期性/延迟性」执行任务,透过设定Schedule的时间频率重覆地去执行任务;

  ‧Background Agent:根据不同的Agent可在细分使用重点,但较属性一次性任务或接收外部事件所触发的任务;

  在Microsoft.Phone.Scheculer针对Scheulde提供了Task与Notification的使用,其用法上Schedule Task又是另一种用途,针对Schedule Notification会在另一篇<>进行说明。

  然而,在Scheulde Task的使用上有几个重要元系一定要去了解的,以下将详细说明:

  A. ScheduledActionService:

  专用于管理该设备所有的Scheduled Actions。Scheduled Actions包括了可用于通知的Alarm、Reminder,更包括下方介绍的二个运行于Background Agent的Periodic Task与Resource-Intensive Task。其重要的方法如下:

名称 说明
Add 向作业系统册一个Scheduled Action。主要透过Scheduled Action的Name做为识别值。
Find 透过特定的Name找出Scheduled Action。
GetActions(Of T) 回传系统中所有特定类型的Scheduled Actions。
LaunchForTest 指定特定的延迟时间与ScheduledTask后,要求Background Agent执行该ScheduledTask。
Remove 从Scheduled Action Service将指定的名称的Scheduled Action移除。
Replace 通常会配合Find找出指定Name的Scheduled Action,并加以取代它。

 

  B. PeriodicTask:

  Periodic(定期) Task是一种定期代理运作的观念,专门针对运作背景任务所需时间较少,而且是执行隔间具有规律期性的情境。

  常见的使用情境,例如:定期上传手机的Location资讯、完成少量资料的同步、更新Tile状态…等。

  B-1. 使用Periodic Task的约束与时间期建议

约束/建议 说明
排程时间间隔:30分 通常每30分执行一次,在电力状况不错的情形下可以配合其他background process使用时,也可以设定接近上下差距10秒的使用。
排程持续时间 通常支援持续执行25秒,但也可能因为其他塬因造成该agent被提早结束。
电池为节约模式时,能防止Exception 由于电池是否要使用节约模式是由用户自行选择。如果该模式被选择时,当电池进入节约模式时,periodic task将有可能无法使用。
每一个设备在Periodic Task的限制 为了让电池最大化使用,不同的设备对电池的使用有一定的控制围,因此,可能限制一个设备最多有几个Agent可以被执行,如果超过,它会自动被turn off。

 

  C. ResourceIntensiveTask:

  Resource-Intensive(资源密集) Task是针对需要相对较长的处理时间,或是遇到需使用大量手机电源、网路等资源时较为适用的类型。

  常见的使用情境,例如:同步大量的资料(如App需要下载大量的资料至手机端才能让App运行)…等。

  C-1. 使用ResourceIntensiveTask的约束与时间期建议

约束/建议 说明
持续时间:10分 通常resource-intensive agent一般执行持续约10分,如果有其他如下方的限制,将会提早停止agent的执行。
外部电力需求 除非设备已连接外部的电力来源,否则无法执行。
无行动网路能线能力 除非设备已通过Wi-Fi、行动网路或连接到PC,否则无法执行。
最小电力需求 除非电力超过90%的情形,否则无法执行resource-intensive agent
设备萤幕被锁定状态 除非电话处于锁定的状态,否则无法执行resource-intensive agent
通话中无法使用 当手机处于通中状态时,resource-intensive agent无法使用。
不能改变网路状态为行动网路 如果resource-intensive agent企图去唿叫AssociateToNetworkInterface(Socket, NetworkInterfaceInfo)来指定任何一种行动网路(GSM或CDMA),则会失败。

 

  这二个元素其实都是由ScheduleAction与ScheduledTask抽象类别实作出来的,它们分别有自身使用的情境与适用性,

  二者最大的差别即在于使用情境与需要耗用手机资源的多少,以及resource-intensive task要在萤幕锁定与电力90%以上才能执行。

  由于使用resource-intensive task要求的限制实在很多,因此,在设计Scheduled Task时需要特别考虑这个部分,至于其他相关的

  属性就大同小异了,以下简介其较长使用到的属性:

名称 说明
Description 设定/取得有关该Scheduled Task的描述。该描述的内容将会出现于手机「Settings/Applications/Background Tasks Settings」的画面中。
如下图:以Background Scheulde为程式名称:
0000 0001
ExpirationTime 设定/取得Scheduled Task到期的时间。
IsScheduled 取得Scheduled Task状态是否为启动。
LastExitReason 取得Agent执行最近一次Task被结束的理由。
LastScheduledTime 取得Agent执行最近一次Task的时间,以手机时间为主。
Name 取得Scheduled Action的名称。

 

  了解了二个元素的基本属性与使用情境后,有几个使用Background Agent要特别注意的:

  1. 一个Application只能有一个Background agent(ScheduledTaskAgent),但Agent可以单独使用PeriodicTask、ResourceIntensiveTask

  或者二个同时使用。要注意的是一个Agent只能有一个PeriodicTask与一个ResourceIntensiveTask。

  2. Background Agent(ScheduledTaskAgent):

  2-1. 透过OnInvoke(ScheduleTask)触发Agent逻辑的部分;

  2-2. 已成功执行完所有任务时,记得唿叫NotifyComplete()告知Agent已完成任务;

  2-3. 如果在执行过程发生错误或是无法执行Task时,要记得唿叫Abort()告知Agent接下来取消运作,然而即可以在Application端取得

  ScheduledTask中的IsScheduled属性为false。但要注意的是如何Abort()之后,要记得使用ShellToast告知用户,以免用户不知道。

  3. Background Agent在记忆体使用量的控制:

  3-1. Periodic agents与resource-intensive agents允许在每次执行Task时,不超过6MB记忆体用量。

  3-2. Audio agents则限制不能超过15MB记忆体用量。

  3-3. 在Debug模式下则不限制,但可以透过API去查询在每一个部分使用记体忆的状况。

  4. 预设Agent为二个星期后需要重新安排Scheduled:

  虽然可以透过ScheduledTask中的LastScheduledTime去确认究竟最近一次执行的Datetime为何,并且使用ExpirationTime去指定Task

  可运行的时间长度。但是使用ScheduledTask可能因为条件限制(例如遇到执行Task时没网路能力,自动要求Agent延后执行),造成Task

  长时间没有被执行,为了确保Task不会一直占住不使用,透过设定2个星期可存活时间,可以自动解决这个问题。设定ExpirationTime可

  在每一次执行Application于前景状况时,进行判断与设定。

  5. Scheduled Agent在连续二个Crash后自动取消:

  由于使用Periodic agents与resource-intensive agetns是交由Agent去控制,因此,当Agent连续出现二次以上的Crash或无法预期的错误,

  该Agent将会被停止,需透过Application回到前景模式再重新启动它。

〉例说明:

  由于Resource-Intensive Task比较不易呈现,因此,例将使用Periodic Task当作主要实作在Background Agent中唿叫Web Service程式,

 

  并且更新Secondary Tile的Background Title与Background Content。

 

  a. 建立一个Web Service,用于ScheduledTaskAgent唿叫时,可以用于更新Tile的内容,撰写完记得发至iis;

 

   1: [WebMethod]
   2: public string GetSystemDatetime()
   3: {
   4:     //回系,示於Tile的Background Content/Title
   5:     return string.Format("system: {0}", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));
   6: }

 

  b. 建立scheduled task agent,并加入Web service参考,设定非同步更新任务;

 

  b-1. 当onInvoke发生时,先宣告Web Service物件并且册Completed事件,最后唿叫Web Service。但要记得先不要加上NotifyComplete(),

 

  因为Agent要执行的任务尚未结束。

 

   1: protected override void OnInvoke(ScheduledTask task)
   2: {
   3:     //TODO: Add code to perform your task in background
   4:     if (task.Name == PTASKNAME)
   5:     {
   6:         //始初化Web Service的Soap Client元素
   7:         BgService.Service1SoapClient tSoapClient = new BgService.Service1SoapClient();
   8:         //Completed要理的任
   9:         tSoapClient.GetSystemDatetimeCompleted += new System.EventHandler<BgService.GetSystemDatetimeCompletedEventArgs>
(tSoapClient_GetSystemDatetimeCompleted);
  10:         tSoapClient.GetSystemDatetimeAsync();
  11:         //此不加上NotifyComplete(),因需要等到Web Service的回值回才算束。
  12:     }
  13:     else
  14:     {
  15:         //如果不是指定的task, 代表不需要行
  16:         NotifyComplete();
  17:     }
  18: }

  b-2. 撰写当Web Service处理完成后,将要更新Secondary Tile的内容;

 

  要注意如果执行完成后,需要在期性执行该任务,记得在加上ScheduledActionService.LaunchForTest的指令;

 

   1: void tSoapClient_GetSystemDatetimeCompleted(object sender, BgService.GetSystemDatetimeCompletedEventArgs e)
   2: {
   3:     if (e.Error == null)
   4:     {
   5:         //找出要更新的Tile且整式
   6:         StandardTileData tTileData = new StandardTileData
   7:         {
   8:             BackgroundImage = new Uri(string.Format("/Images/{0}.png", "taipei"), UriKind.Relative),
   9:             Title = "Bg Sample",
  10:             Count = 0,
  11:             BackTitle = "取得service",
  12:             BackContent = e.Result,
  13:             BackBackgroundImage = new Uri("/Images/red.png", UriKind.Relative)
  14:         };
  15:         ShellTile tUsedTile = ShellTile.ActiveTiles.FirstOrDefault(
  16:                           tX => tX.NavigationUri.ToString().Contains(string.Format("Key={0}", PTASKNAME)));
  17:         if (tUsedTile != null)
  18:         {
  19:             tUsedTile.Update(tTileData);
  20:         }
  21:         //如果需要期性行,需要加上下方程式段
  22:         //ScheduledActionService.LaunchForTest(PTASKNAME, TimeSpan.FromSeconds(10));
  23:     }
  24:     else
  25:     {
  26:         //生也要送出Toast告用
  27:         ShellToast toast = new ShellToast();
  28:         toast.Title = "Error";
  29:         toast.Content = e.Error.Message;
  30:         toast.Show();
  31:     }
  32:     NotifyComplete();
  33: }

  c. 建立Application,加上建立tile与启动periodic task的功能,并且将scheduled task agent与Web Service加入专案参考;

 

  c-1. 撰写按钮事件,在确认Tile中没有指定的Key时才可以建立ScheduledTask与Tile;

 

   1: private void Button_Click(object sender, RoutedEventArgs e)
   2: {
   3:  
   4:     ShellTile tUsedTile = ShellTile.ActiveTiles.FirstOrDefault(
   5:                           tX => tX.NavigationUri.ToString().Contains(string.Format("Key={0}", PTASKNAME)));
   6:     if (tUsedTile == null)
   7:     {
   8:         //Scheduled Task Agent
   9:         gPeriodicTask = new PeriodicTask(PTASKNAME);
  10:         gPeriodicTask.Description = "BgScheduledAction Sample, update tile by webserivce";
  11:         ScheduledActionService.Add(gPeriodicTask);
  12:         PeriodicStackPanel.DataContext = gPeriodicTask;
  13:         ScheduledActionService.LaunchForTest(PTASKNAME, TimeSpan.FromSeconds(10));
  14:  
  15:         //加入tile
  16:         StandardTileData tTileData = new StandardTileData
  17:         {
  18:             BackgroundImage = new Uri(string.Format("/Images/{0}.png", "taipei"), UriKind.Relative),
  19:             Title = "Bg Sample",
  20:             Count = 0,
  21:             BackTitle = "null",
  22:             BackContent = "null",
  23:             BackBackgroundImage = new Uri("/Images/red.png", UriKind.Relative)
  24:         };
  25:         //建立Secondary Tile,且指定Tile後要的Page
  26:         Uri tUrl = new Uri(string.Format("/MainPage.xaml?Key={0}", PTASKNAME), UriKind.Relative);
  27:         ShellTile.Create(tUrl, tTileData);
  28:     }
  29:     else
  30:     {
  31:         MessageBox.Show("the PeriodicTask already existed!!");
  32:     }
  33: }

  c-2. 撰写在画面启动时,自动取得指定的ScheduledAction,并且Bind到画面的元件;

 

   1: // Constructor
   2: public MainPage()
   3: {
   4:     InitializeComponent();
   5:     
   6:     //搜指定的Scheduled Task Name
   7:     ScheduledAction tTask = ScheduledActionService.Find(PTASKNAME);
   8:     if (tTask != null)
   9:     {
  10:         //行Data binding
  11:         gPeriodicTask = tTask as PeriodicTask;
  12:         PeriodicStackPanel.DataContext = gPeriodicTask;
  13:     }
  14: }

  c-3. 撰写当点击Checked = false时,要移除指定的Scheduled Task;

 

   1: private void PeriodicCheckBox_Unchecked(object sender, RoutedEventArgs e)
   2: {
   3:     //移掉PeriodicTask
   4:     ScheduledAction tTask = ScheduledActionService.Find(PTASKNAME);
   5:     if (tTask != null)
   6:         ScheduledActionService.Remove(PTASKNAME);
   7: }

  d. 测试流程

 

  d-1. 开启程式,点击「Start Periodic Agent , Create Tile」;

 

  d-2. 建立Tile后,重新点击程式即可以看到Periodic Agent的状态;

 

  d-3. 按Start回到Start Page注意Tile的background content与title由null为有值;

 

  如下图:

 

0002003

 

 

 

源码下载

 

 

 

  以上是分享撰写Background Schedule Task的应用,这个Agent让App可以向系统册一些定期要产生的讯息,那也有在XDA上看过有人撰写相似Schedule Task的应用,它能直接操作画面中的资料,我是觉得非常厉害的,它用的是Native-Code的方式,让Schedule Task可以唿叫来撷取画面资料。但这个方法更详细的说明,我自己也还没有非常的搞懂。所以WP7未来更多的API将会使它更符合大家的应用。

 

  本文来自pou的博客,原文地址:http://www.dotblogs.com.tw/pou/archive/2011/11/27/59664.aspx

posted on 2012-04-30 18:14  _eagle  阅读(1140)  评论(0编辑  收藏  举报