2015-09-27 65 views
7

如果前台应用程序正在执行,如何防止后台任务运行?为我的应用程序使用通用Windows平台。Windows 10 UWP - 如果前台应用程序正在运行,则停止后台任务

我的后台任务是检查某个站点上的新项目,并在有新事物可用时发送敬酒,但是如果用户现在正在运行应用程序,我不想防止发送敬酒。

我试图在应用程序启动时取消注册任务,并在应用程序终止时再次注册,这对我来说不是很好的解决方案 - 当设备由于某种原因而关闭时(例如,电池被移除),我的任务将不会被注册,直到应用程序再次启动。

谢谢。

+1

您是否找到解决方案?你在使用应用程序触发任务吗? – peterincumbria

回答

0

我会很乐意看到一个更简单的解决方案。除此之外,你可以建立仲裁机制。沿着这些路线的东西:

public class AppSynchronization 
{ 
    // Called by the main app on launch or on resume. It will signal the main app's intention to start. 
    // The main app will not perform any significant actions before this method returns. 
    public void ActivateMainApp() {...} 

    // Called by the main app. It will signal the fact that the main app is "going away". 
    public async Task MainAppSuspended() {...} 

    // Called by the background agent. 
    // It will signal the background agent intention to start. 
    // This method will only return if the main app is out of the way. 
    // It will return a cancellation token that will be used to cancel the activity of the background agent when the main app advertises its intention to start. 
    public async Task<CancellationToken> ActivateBackgroundAgent(CancellationToken cancelWait) 
    { 
     // Make sure the main app is not started or wait until the main app is out of the way 

     // Start a thread that is on the lookout for the main app announcing that it wants to start. 
     // When that happens it will cancel the cancellation token returned. 
    } 

    // <summary> 
    // Called by the background agent. 
    // It will signal the fact that the background agent completed its actions. 
    public async Task DeactivateBackgroundAgent() 
} 

在主应用程序:

private AppSynchronization appSynchronization; 

public App() 
{ 
    ... 
    this.appSynchronization = new AppSynchronization(); 
} 

protected async override void OnLaunched(LaunchActivatedEventArgs e) 
{ 
    ... 
    if (rootFrame.Content == null) 
    { 
     // Advertise the fact that the main app wants to start. 
     // The background agent will know to cancel whatever its doing. 
     // ActivateMainApp may have to be async although you need to make sure that OnLaunched supports that 
     this.appSynchronization.ActivateMainApp(); 
     ... 
    } 
} 

private async void OnResuming(object sender, object e) 
{ 
    ... 
    // Advertise the fact that the main app wants to resume. 
    // The background agent will know to cancel whatever its doing. 
    this.appSynchronization.ActivateMainApp(); 
} 


private async void OnSuspending(object sender, SuspendingEventArgs e) 
{ 
    var deferral = e.SuspendingOperation.GetDeferral(); 

    ... 
    // Advertise the fact that the main app is suspending. 
    // The background agent will know it is allowed to start doing work. 
    await _mainAppSynchronization.MainAppSuspended(); 

    ... 
    deferral.Complete(); 
} 

private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) 
{ 
    ... 
    // Advertise the fact that the main app is going away. 
    // The background agent will know it is allowed to start doing work. 
    _mainAppSynchronization.MainAppSuspended().Wait(); 
} 

,并在后台代理:

public sealed class BackgroundTask : IBackgroundTask 
{ 
    public async void Run(IBackgroundTaskInstance taskInstance) 
    { 
     ... 
     AppSynchronization appSynchronization = new AppSynchronization(); 
     BackgroundTaskDeferral deferral = taskInstance.GetDeferral(); 

     // Make sure that the main app is not started. If it is started then wait until the main app gets out of the way. 
     // It he main app is running this will wait indefinitely. 
     // Use backgroundAgentCancellationToken to cancel the actions of the background agent when the main app advertises its intention to start. 
     CancellationToken backgroundAgentCancellationToken = await appSynchronization.ActivateBackgroundAgent(); 

     await DoBackgroundAgentWork(backgroundAgentCancellationToken) 

     // Advertise the fact that the background agent is out. 
     // DeactivateBackgroundAgent will make sure that the synchronization mechanism advertised the fact that the background agent is out. 
     // DeactivateBackgroundAgent may have to be declared async in case the synchronization mechanism uses async code to do what is needed. 
     await appSynchronization.DeactivateBackgroundAgent(); 

     deferral.Complete(); 
    } 

我不知道是否有任何方式跨越进程通信在UWP。仲裁机制本身可能必须基于本地存储上的文件。

如果一个或另一个进程以灾难性方式崩溃,仲裁机制可能必须包含一个心跳机制。

+0

“如果主应用程序正在运行,则将无限期等待。” (在bg任务中)。你确定吗?如果运行时间过长,后台任务是否会被终止?还是等待不算CPU使用率?如果可能的话,希望得到一些见解。谢谢:) – sibbl

+0

如果在ActivateBackgroundAgent中实现的仲裁机制有一个休眠几秒钟的循环,然后检查主应用程序的状态(也许通过检查主应用程序创建的文件的存在),那么CPU使用率将是很小。睡眠时间不计算在内。最终,后台代理将被暂停,然后您需要等待一段时间才能让操作系统再次恢复。尽管如此,你将不得不做很多测试。据我所知,Windows 8.1和WP 8.1中的后台代理有重要的区别。不确定UWP。 – Ladi

+0

在UWP中,如果DeviceUseTrigger不是触发器,则在应用程序触发器的情况下,后台任务将在10分钟后取消。由于SensorCore现在已被弃用,这使我对GPS跟踪应用程序感到非常痛苦。 – peterincumbria

1

使用一个名为互斥前台应用程序和后台代理

0

我有一个由TimeTrigger触发backgroundtask之间进行同步。该任务在手机重新启动后自动重启,无需首先加载应用程序。也许这将有助于...

[编辑]刚发现我迟到了我的回答...

0

您可以使用下面的代码检查应用程序的状态

var value = ApplicationSettingsHelper.ReadResetSettingsValue(ApplicationSettingsConstants.AppState); 
if (value == null) 
    foregroundAppState = AppState.Unknown; 
else 
    foregroundAppState = EnumHelper.Parse<AppState>(value.ToString()); 

if (foregroundAppState == AppState.Suspended) 
     //Do something 
else if (foregroundAppState == AppState.Active) 
     return; 
else if (foregroundAppState == AppState.Unknown) 
     return; 
0

的这样做的方法是使用应用程序本地设置。

在前景和背景中设置设置。 作为前景中的一个示例,请执行此操作。

/// <summary> 
/// When the window visibility changes 
/// </summary> 
/// <param name="sender">object sender</param> 
/// <param name="e">VisibilityChangedEventArgs e</param> 
private void OnVisibilityChanged(object sender, VisibilityChangedEventArgs e) 
{ 
    var localSettings = ApplicationData.Current.LocalSettings; 

    if (!e.Visible) 
    { 
     localSettings.Values["AppInForeground"] = false;    
    } 
    else 
    { 
     localSettings.Values["AppInForeground"] = true; 
    } 
} 

不幸sibbi是正确的,如果你不使用DeviceUseTrigger 10分钟后您的后台任务将取消。

0

这类似于这样的问题:How to stop the background task if the app is starting?

最简单的方法是将你的任务转化为进程内的后台任务:https://docs.microsoft.com/en-us/windows/uwp/launch-resume/convert-out-of-process-background-task

随着进程内的任务,你可以检查应用程序是否是在前台或不直接从后台活动。

如果你需要保持你的后台任务分开处理的,从你的主应用程序,那么你可以做下列之一:

  • 通过创建一个文件的互斥。
  • 创建一个进程内应用程序服务并尝试从后台任务与其通信。然后,您可以返回一个值,无论该应用程序是否在前台。
  • 使用应用程序本地设置词典来保存关于前台应用程序是否正在运行的标志。这是最脆弱的,因为应用程序崩溃可能会导致标志无法正确重置。