Windows Phone 8.1后台任务和前台应用通信

3
我正在开发一个Windows Phone 8.1应用程序,为每小时运行注册了后台任务计时器触发器。因此,后台任务每60分钟唤醒并执行某些操作。
我的问题是,当后台任务正在进行时,如果用户唤醒应用程序,我们是否有办法向用户显示后台任务进程中正在发生的事情?
我知道它们是两个不同的进程。我使用Silverlight 8.1项目作为前台应用程序,并使用托管的Windows运行时项目作为后台任务。我使用Silverlight应用程序注册后台任务,但现在我在思考如何在这两个进程之间创建通信桥梁。
有任何线索吗?这种做法可行吗?
2个回答

5
这里有一些与应用程序和其后台任务之间通信相关的想法(或信息)。
  • 您可以使用IBackgroundTaskRegistration对象的Progress和Completed事件。您可以使用BackgroundTaskRegistration.AllTasks获取该对象 - 此属性返回应用程序注册的后台任务列表。每次运行应用程序时,您都必须订阅这些事件。

    从后台任务中,您可以将IBackgroundTaskInstance对象的Progress属性设置为某个UInt32值,然后应用程序将接收到该事件。也许您可以在该数字中编码您所需的内容。例如:1表示任务正在初始化,2表示任务正在执行WorkA等等...

  • 两个进程都可以访问相同的文件,因此您可能可以利用这一点。

  • 使用Mutex来同步两个进程之间的代码执行。

那就是我现在能想到的。希望对你有所帮助。

附言:我没有真正尝试过这些事件,但它们似乎可能很有用。


谢谢Yasen。这是一个很好的思路。我会去查看一下。 我也在考虑类似的方法,使用Windows.Storage本地设置来存储布尔值,并在计划同步进行时将其设置为true,在完成后将其设置为false。这样,当前台应用程序打开时,用户会收到通知,告诉他们后台正在进行某些操作。 - golldy
2
如果您只想知道后台任务是否正在运行,可以使用 Mutex。在后台任务运行时,获取 Mutex 上的锁。当您想从应用程序中检查它时,请尝试使用 mutex.WaitOne(0) 获取 Mutex 上的锁。此调用会立即尝试获取锁(而不等待某个人释放它)。如果成功,则返回 true,否则返回 false。如果结果为 false,则锁已被其他人获取 - 即后台任务。 - yasen

1

我已经在后台任务和应用程序之间进行了一些POC通信。我使用的是Windows通用应用程序,但它也适用于Silverlight手机应用程序。

private IBackgroundTaskRegistration timeZoonChangeTask;
    public MainPage() 
    {
        this.InitializeComponent();

        NavigationHelper nvHelper = new NavigationHelper(this);
        IReadOnlyDictionary<Guid, IBackgroundTaskRegistration> allTasks = BackgroundTaskRegistration.AllTasks;
        if (allTasks.Count() == 0)
        {
            lblMessage.Text = "No Task is registered at the moment";
        }
        else//Task already registered
        {
            lblMessage.Text = "Timezoon Task is registered";
            this.GetTask();
        }
    }

    /// <summary>
    /// Time zoon task registration.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        await BackgroundExecutionManager.RequestAccessAsync();

        BackgroundTaskBuilder taskBuilder = new BackgroundTaskBuilder();
        taskBuilder.Name = "MyBackgroundTask";

        SystemTrigger systemTrigger = new SystemTrigger(SystemTriggerType.TimeZoneChange, false);
        taskBuilder.SetTrigger(systemTrigger);

        taskBuilder.TaskEntryPoint = typeof(MyBackgroundTask.TheTask).FullName;
        taskBuilder.Register();
        lblMessage.Text = "Timezoon Task is registered";


        this.GetTask();

    }

/// Get registered task and handel completed and progress changed events.
    /// </summary>
    private void GetTask()
    {
        var timeZoonChangeTask = BackgroundTaskRegistration.AllTasks.Values.FirstOrDefault();
        timeZoonChangeTask.Completed += timeZoonChangeTask_Completed;
        timeZoonChangeTask.Progress += timeZoonChangeTask_Progress;

    }

    /// <summary>
    /// raised when task progress is changed app is active
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    void timeZoonChangeTask_Progress(BackgroundTaskRegistration sender, BackgroundTaskProgressEventArgs args)
    {
        this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
        {
            lblTaskProgress.Text = args.Progress.ToString() + "%";
            recProgress.Width = 400 * (double.Parse(args.Progress.ToString()) / 100);
        });
        //this.Dispatcher.BeginInvoke(() =>
        //    {

        //    });
    }

    /// <summary>
    /// Raised when task is completed and app is forground
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    void timeZoonChangeTask_Completed(BackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs args)
    {
        this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
          {
              lblMessage.Text = "Task Excecution is completed";
          });
    }

and below is the task class

public sealed class TheTask:IBackgroundTask
{
    public async void Run(IBackgroundTaskInstance taskInstance)
    {
        ///Get Deferral if we are doing aysnc work. otherwise it will not work. 
        //Always get deferral it will not harm.
        var deferral = taskInstance.GetDeferral();


        taskInstance.Canceled += taskInstance_Canceled;

        for (uint i = 0; i < 10; i++)
        {
            taskInstance.Progress = i + 10;
            await Task.Delay(2000);
        }

        //Write last run time somewhere so the gorground app know that at when last time this backgournd app ran.

        ///Set this progress to show the progesss on the forground app if it is running and you want to show it.
        taskInstance.Progress = 0;

        deferral.Complete();
    }

    void taskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
    {

    }
}

穆罕默德,干得好。 我所做的问题在于,考虑我正在将联系人同步到服务器。我将无法显示联系人上传的上传进度,我只能显示后台任务的进度。我刚刚意识到BackgroundTaskProgressEventArgs具有进度属性,可以仅处理后台任务本身的进度,而不是后台任务中正在发生的事情。这是一个限制,我可以说。 - golldy
1
@golldy Progress 属性有 32 位。这不算太多,但你可以在里面放两三个数字。也许这能让你同时知道正在发生什么以及进度如何? - yasen
1
@golldy,正如yasen所建议的那样,您可以使用一些枚举来显示您想要的进度类型。例如,当所有以“a”开头的联系人都上传时,触发进度事件YourEnum.AComplete,并在您的应用程序中显示消息,表示所有A联系人都已上传。就像这样的东西。 - Muhammad Saifullah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接