IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Windows 10 UWP开发:如何定时触发后台任务

    汪宇杰发表于 2015-11-24 06:10:00
    love 0

    今天在爆UWP的定时后台任务,坑有点多,爆出屎来了。有的坑在很多网上的文章里都没提到,非常的坑。刚刚开荒成功了,把经验写出来分享:

    1. 写一个后台任务的类,继承IBackgroundTask接口

    通常,在设计应用程序结构的时候,我们会建类库项目(Class Library)放这些类。比如 FarkBackgroundTask.Core

    因为是UWP工程,所以建的类库也要是Universal Windows的。注意,这里我们已经埋下了一个巨坑,稍后会解释。

    我们的类代码如下:

    public class SayFarkTask : IBackgroundTask
    {
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            Debug.Write("================ Fark the farking farkers ================");
        }
    }

    里面这个Run方法,就是执行任务用的,是接口里的方法。现在,我们又埋下了一个巨坑。

    2. 在manifest文件里添加后台任务声明

    对应的代码是:

    <Extensions>
      <Extension Category="windows.backgroundTasks" EntryPoint="FarkBackgroundTask.Core.SayFarkTask">
        <BackgroundTasks>
          <Task Type="timer" />
        </BackgroundTasks>
      </Extension>
    </Extensions>

    3. 在应用程序启动的时候注册后台任务

    踩过一堆小坑之后,封装了一个注册方法:

    public static async Task<BackgroundTaskRegistration> RegisterBackgroundTask(Type taskEntryPoint,
                                                                    string taskName,
                                                                    IBackgroundTrigger trigger,
                                                                    IBackgroundCondition condition)
    {
        var status = await BackgroundExecutionManager.RequestAccessAsync();
        if (status == BackgroundAccessStatus.Unspecified || status == BackgroundAccessStatus.Denied)
        {
            return null;
        }
    
        foreach (var cur in BackgroundTaskRegistration.AllTasks)
        {
            if (cur.Value.Name == taskName)
            {
                cur.Value.Unregister(true);
            }
        }
    
        var builder = new BackgroundTaskBuilder
        {
            Name = taskName,
            TaskEntryPoint = taskEntryPoint.FullName
        };
    
        builder.SetTrigger(trigger);
    
        if (condition != null)
        {
            builder.AddCondition(condition);
        }
    
        BackgroundTaskRegistration task = builder.Register();
    
        Debug.WriteLine($"Task {taskName} registered successfully.");
    
        return task;
    }

    主要有几点小坑:

    1. 先得请求权限,timer的任务是需要权限的

    2. 如果注册过,建议先清除注册,再重新注册一次。这里我的��码和MSDN上的例子不太一样了,MSDN的做法是foreach里检查到name一样的就return那个task,但是我考虑的是如果你的task注册行为有变化就不好管理了,所以干脆全删了重建一个新的。

    3. 入口点EntryPoint的类型我改用了Type,好处是强类型,编译时就知道会不会爆,防止手滑。MSDN的例子是用string的,容易改爆。

    现在就可以在App.xaml.cs里面注册了:

    private async Task RegisterBackgroundTask()
    {
        var task = await RegisterBackgroundTask(
            typeof(FarkBackgroundTask.Core.SayFarkTask),
            "SayFarkTask",
            new TimeTrigger(15, false),
            null);
    
        task.Progress += TaskOnProgress;
        task.Completed += TaskOnCompleted;
    }

    在protected override async void OnLaunched(LaunchActivatedEventArgs e)里面:

    ...
    Window.Current.Content = rootFrame;
    await RegisterBackgroundTask();
    ...

    现在看上去一切都是好的,然而运行就会爆出屎来,你会发现Task怎么也激活不了。这是因为之前埋下了2个巨坑。

    4. 巨坑之一 sealed 类

    因为一个神奇的原因,我们的后台任务类SayFarkTask如果不是sealed,就会爆。所以得改成:

    public sealed class SayFarkTask : IBackgroundTask
    ...

    现在运行还是会爆,爆了我2个多小时候,我发现了个巨坑!简直坑得史无前例……

    5. 巨坑之二 Windows Runtime Component

    在我们建类库的时候,选的Universal Windows没错,但是它的输出类型是Class Library,我们平时写应用确实一直在用Class Library,但是这里不行,必须改成Windows Runtime Component,不然就爆!!!

    坑就坑在MSDN下载的范例里面一下子也发现不了,毕竟在VS里显示的时候都叫(Universal Windows)……

    6. 现在执行应用程序,在VS的lifecycle events里选我们的SayFarkTask就能跑出结果了

     



沪ICP备19023445号-2号
友情链接