博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

07,Windows Phone后台代理

Posted on 2012-12-12 22:32  淡如水wp  阅读(2647)  评论(2编辑  收藏  举报

内容预告:

  • Windows Phone 任务管理
  • 用后台代码实现多任务
  • 在Visual Studio中创建任务
  • 文件传输任务
  • 后台提醒
  • 后台音乐播放

前台任务:一般来说,一个Windows Phone应用程序运行在前台时,它可以与用户直接交互,但同时只能有一个程序运行在前台,是为了保证性能和电量。

后台代理:Windows Phone应用程序可以开启一个后台代理,类型可以是定期执行或资源密集型或两者兼俱型,但每个程序只能有一个后台代理。后台代理和前台程序运行在后台不是一回事,后台代理只能做有限的事情。

后台代理的限制:在Windows Phone系统上同时可运行后台代理的数量有限的,且只有在条件允许的情况下操作系统才把CPU的控制权交给后台代理,省电模式下不能运行,用户可以自己关闭。

代理和任务:一个任务是操作系统管理的在某个约定的时间执行的,有定期执行或资源密集型两种。一个后台代理是真正要执行的代码,代理代码从BackgroundTask派生,是计划任务代理项目的一部分。

定期任务:大约每30分钟执行一次,每次大约25秒,内存使用量小于6MB,两次crash连续后会取消,同时活跃的任务数量有限制,适用于定位跟踪,后台轮询,磁贴更新。

资源密集型任务:外接电源时,电量大于90%,WiFi,锁屏状态,可连续运行10分钟,内存使用量小于6MB,两次crash连续后会取消,适合同步服务,解压缩,压缩数据库。

兼俱型任务:可以用一个后台任务类运行两种任务,系统会根据上下文判断执行合适的任务。

后台代理功能:

定位跟踪器:用后台代理以日志文件的方式存储有规律地存储手机的坐标,代理会在日志程序没有焦点的时候更新位置数据。

创建后台代理:

连接代理项目:船长日志项目引用了一个定位任务项目的输出,前台程序不直接引用任何代理类的对象或类。

后台代理代码:必须实现OnInvode函数,它完成时会通知运行时系统。

namespace LocationLogTaskAgent
{
    public class ScheduledAgent : ScheduledTaskAgent
    {
        protected override void OnInvoke(ScheduledTask task)
        {
            //TODO: Add code to perform your task in background
            NotifyComplete();
        }
    }
}

 

与后台代理共享数据:通过独立存储

protected override void OnInvoke(ScheduledTask task)
{
    string message ="";
    string logString = "";
    if (LoadLogFromIsolatedStorageFile() {
        message = "Loaded";
    }
    else {
        message = "Initialised";
    }    ...
}

并发数据存储:用互斥量(Mutex)保护存储文件,保证释放mutex。

public bool LoadLogFromIsolatedStorageFile()
{
    mut.WaitOne(); // Wait until it is safe to enter

    try  {          // read the file here
          return true;
    }
    catch { 
          LogText = ""; 
          return false;
    }
    finally {
        mut.ReleaseMutex(); // Release the Mutex. 
    }
}

钩选定位能力:

获取手机位置:通过GeoCoordinateWatcher类提供位置信息,在后台代理中使用Position,其每15分钟更新一次。

protected override void OnInvoke(ScheduledTask task)
{
    ...
    GeoCoordinateWatcher watcher = new GeoCoordinateWatcher();
    watcher.Start();
    string positionString = watcher.Position.Location.ToString() + 
                            System.Environment.NewLine;
    ...
}

存储手机位置:

protected override void OnInvoke(ScheduledTask task)
{
    ...
    logString = logString + timeStampString + " " + positionString;

    SaveLogToIsolatedStorageFile ();
    ...
}

显示通知:后台任务可以弹出toast提醒,如果用户点击toast,可以启动程序,Toast消息会在程序激活后消失。

protected override void OnInvoke(ScheduledTask task)
{
    ...
    logString = logString + timeStampString + " " + positionString;

    SaveLogToIsolatedStorageFile ();
    ...
}

安排一个后台代理:

PeriodicTask t;
t = ScheduledActionService.Find(taskName) as PeriodicTask;
bool found = (t != null);
if (!found)             
{
    t new PeriodicTask(taskName);
}
t.Description = description;
t.ExpirationTime = DateTime.Now.AddDays(10);
if (!found)
{
    ScheduledActionService.Add(t);
}             
else
{
    ScheduledActionService.Remove(taskName);
    ScheduledActionService.Add(t);
}

调试后台任务:我们可以强制服务启动代理,因为30分钟才能执行一次太烦人了。

#if DEBUG_AGENT
 ScheduledActionService.LaunchForTest(taskName, TimeSpan.FromSeconds(60));
#endif

Tips:

  • 经常续订,因为后台任务只能持续2周有效。
  • 不实现后台代理的临界功能,因为用户可能禁用,系统也可能因为电量原理挂起程序。
  • 如果需要稳定的更新磁贴或Toast消息,考虑用推送。

文件传输任务:程序不运行也可以传输,可以监视下载状态,支持HTTP、HTTPS,但不支持FTP。

传输限制:上传最大5MB,通过手机网络下载最大20MB,通过WiFi最大100MB,这些数字可以通过修改TransferPreferences的值。每个程序最多可以请求25次。

后台传输命名空间:using Microsoft.Phone.BackgroundTransfer;

创建一个后台传输:POST用来发送文件到服务器。

Uri transferUri = new Uri(Uri.EscapeUriString(transferFileName), UriKind.RelativeOrAbsolute);
// Create the new transfer request, passing in the URI of the file to 
// be transferred.
transferRequest = new BackgroundTransferRequest(transferUri);

// Set the transfer method. GET and POST are supported.
transferRequest.Method = "GET";

设置传输目标:

string downloadFile = transferFileName.Substring(transferFileName.LastIndexOf("/") + 1);
// Build the URI
downloadUri = new Uri("shared/transfers/" + downloadFile, UriKind.RelativeOrAbsolute);
transferRequest.DownloadLocation = downloadUri;

// Set transfer options
transferRequest.TransferPreferences = TransferPreferences.AllowCellularAndBattery;

开始传输:

try {
    BackgroundTransferService.Add(transferRequest);
}
catch (InvalidOperationException ex) {
    MessageBox.Show("Unable to add background transfer request. " 
                                                             + ex.Message);
}
catch (Exception) {
    MessageBox.Show("Unable to add background transfer request.");
}

监视传输:TransferProcessChanged是为进度条准备的,TransferStatusChanged在完成或失败时触发。

// Bind event handlers to the progess and status changed events
transferRequest.TransferProgressChanged += 
    new EventHandler<BackgroundTransferEventArgs>(
        request_TransferProgressChanged);

transferRequest.TransferStatusChanged += 
    new EventHandler<BackgroundTransferEventArgs>(
        request_TransferStatusChanged);
void request_TransferProgressChanged(object sender, 
                                     BackgroundTransferEventArgs e)
{
    statusTextBlock.Text = e.Request.BytesReceived + " received.";
}
void request_TransferStatusChanged(object sender, BackgroundTransferEventArgs e) {
  switch (e.Request.TransferStatus) {
     case TransferStatus.Completed:
         // If the status code of a completed transfer is 200 or 206, the
         // transfer was successful
         if (transferRequest.StatusCode == 200 ||transferRequest.StatusCode == 206)
         {
            // File has arrived OK – use it in the program
         }

移除一个传输:

try {
    BackgroundTransferService.Remove(transferRequest);
}
catch {
}

声音播放代理:声音流可以存在独立存储内,机制与其他后台任务相同。