2015-09-27 95 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

隨着進程內的任務,你可以檢查應用程序是否是在前臺或不直接從後臺活動。

如果你需要保持你的後臺任務分開處理的,從你的主應用程序,那麼你可以做下列之一:

  • 通過創建一個文件的互斥。
  • 創建一個進程內應用程序服務並嘗試從後臺任務與其通信。然後,您可以返回一個值,無論該應用程序是否在前臺。
  • 使用應用程序本地設置詞典來保存關於前臺應用程序是否正在運行的標誌。這是最脆弱的,因爲應用程序崩潰可能會導致標誌無法正確重置。