扩展执行无法正常工作?

我无法使ExtendedExecution正常工作。 问题是在执行完成之前不会触发Revoked事件。 如果我们采样:

 private async void OnSuspending(object sender, SuspendingEventArgs e) { Debug.WriteLine("Suspending in app"); var deferral = e.SuspendingOperation.GetDeferral(); using (var session = new ExtendedExecutionSession()) { session.Reason = ExtendedExecutionReason.SavingData; session.Description = "Upload Data"; session.Revoked += (s, a) => { Debug.WriteLine($"Extended execution revoked because of {a.Reason}"); }; var result = await session.RequestExtensionAsync(); if (result == ExtendedExecutionResult.Denied) Debug.WriteLine("Extended execution failed"); else { Debug.WriteLine("Executing"); await Task.Run(() => { Task.Delay(9000).Wait(); Debug.WriteLine("Finished the task"); }); Debug.WriteLine("Executing finished"); } Debug.WriteLine("Suspending after execution"); } deferral.Complete(); } 

文档指出应该在恢复应用程序时触发Revoked事件,但是如果您尝试附加调试器的代码,那么您将看到调试输出看起来没问题,但您必须等待9000毫秒才能显示它。 这意味着代码将暂停,直到会话结束。

最大的问题是如果你在没有连接调试器的情况下启动它,启动应用程序,暂停然后恢复,你会看到一个黑屏几秒钟,然后操作系统将终止你的应用程序。

我错过了什么吗? 有没有人让它正常工作?

awaitTask的使用导致您的继续任务保留在主线程上,使您必须等待黑屏。 请记住, await行为是将执行安排到Dispatcher ,而不是开始新线程,NOR将其执行安排到ThreadPool中。 因此,在Delay()结束之前,不能再处理UI消息。

只需在新线程上执行耗时的操作,但要确保会话保持打开状态直到结束。

看看这个https://msdn.microsoft.com/en-us/magazine/jj991977.aspx ,以便更好地了解执行是如何进行的

没有UI问题或任何事情。 你的代码有效。 你的期望是错误的。

使用您正在告诉您的应用程序的ExtendedExecutionSession ,您需要时间进行保存,并且在完成之前不会撤消。 在你的情况下大约需要9秒。

尝试暂停应用程序,等待10秒然后撤消它。 它会立即发生。 然后尝试暂停应用程序并在会话结束前撤消它。 现在, ExtendedExecutionSession将告诉您的操作系统您的应用程序尚未被撤销,并且必须等到保存过程完成。 那正是你想要的。

请参阅有关扩展执行的Microsoft doc :

在应用程序处于挂起状态时请求ExtendedExecutionReason.SavingData扩展执行会话会产生您应该注意的潜在问题。 如果在Suspending状态下请求扩展执行会话,并且用户请求再次启动应用程序,则可能需要很长时间才能启动。 这是因为扩展的执行会话时间段必须在关闭应用程序的旧实例并且可以启动应用程序的新实例之前完成。 牺牲启动性能时间以保证用户状态不会丢失。

关于“撤销”部分中提到的内容对您而言也很有趣:

当为ExtendedExecutionReason.SavingData扩展执行会话触发Revoked事件时,应用程序有一秒钟完成它正在执行的操作并完成Suspending。

一秒钟不足以完成你的9秒等待。

要消除延迟显示调试输出的可能性,可以通过将当前时间添加到输出来测试它。 操作系统可能存在会话未正确关闭的问题,因为9秒没有完成。

另请注意EnterBackground上的注释 :

以前,在用户完成与您的应用的会话后,您的暂停回拨是保存状态的最佳位置。 但是,现在应用程序可以继续在后台运行,然后由于触发器活动而返回到前台,而不会达到挂起状态。 用户会话之后保存数据的最佳位置是在输入的后台事件处理程序中。

如果触发Exiting事件,您可能希望执行代码。

对于OnSuspending尝试在撤销发生时立即执行等待for循环中断(取消保存过程),一次只等待半秒钟。

更新:

…或者使用后台任务 ,因为暂停似乎是终止前唯一可靠的警告:

 // // Declare that your background task's Run method makes asynchronous calls by // using the async keyword. // public async void Run(IBackgroundTaskInstance taskInstance) { // // Create the deferral by requesting it from the task instance. // BackgroundTaskDeferral deferral = taskInstance.GetDeferral(); // // Call asynchronous method(s) using the await keyword. // var result = await ExampleMethodAsync(); // // Once the asynchronous method(s) are done, close the deferral. // deferral.Complete(); } 

更新2

对于应该如何完成的“正确”方式,请参阅官方示例 :

 private async void OnSuspending(object sender, SuspendingEventArgs args) { suspendDeferral = args.SuspendingOperation.GetDeferral(); rootPage.NotifyUser("", NotifyType.StatusMessage); using (var session = new ExtendedExecutionSession()) { session.Reason = ExtendedExecutionReason.SavingData; session.Description = "Pretending to save data to slow storage."; session.Revoked += ExtendedExecutionSessionRevoked; ExtendedExecutionResult result = await session.RequestExtensionAsync(); switch (result) { case ExtendedExecutionResult.Allowed: // We can perform a longer save operation (eg, upload to the cloud). try { MainPage.DisplayToast("Performing a long save operation."); cancellationTokenSource = new CancellationTokenSource(); await Task.Delay(TimeSpan.FromSeconds(10), cancellationTokenSource.Token); MainPage.DisplayToast("Still saving."); await Task.Delay(TimeSpan.FromSeconds(10), cancellationTokenSource.Token); MainPage.DisplayToast("Long save complete."); } catch (TaskCanceledException) { } break; default: case ExtendedExecutionResult.Denied: // We must perform a fast save operation. MainPage.DisplayToast("Performing a fast save operation."); await Task.Delay(TimeSpan.FromSeconds(1)); MainPage.DisplayToast("Fast save complete."); break; } session.Revoked -= ExtendedExecutionSessionRevoked; } suspendDeferral?.Complete(); suspendDeferral = null; } private async void ExtendedExecutionSessionRevoked(object sender, ExtendedExecutionRevokedEventArgs args) { //If session is revoked, make the OnSuspending event handler stop or the application will be terminated if (cancellationTokenSource != null){ cancellationTokenSource.Cancel(); } await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { switch (args.Reason) { case ExtendedExecutionRevokedReason.Resumed: // A resumed app has returned to the foreground rootPage.NotifyUser("Extended execution revoked due to returning to foreground.", NotifyType.StatusMessage); break; case ExtendedExecutionRevokedReason.SystemPolicy: //An app can be in the foreground or background when a revocation due to system policy occurs MainPage.DisplayToast("Extended execution revoked due to system policy."); rootPage.NotifyUser("Extended execution revoked due to system policy.", NotifyType.StatusMessage); break; } suspendDeferral?.Complete(); suspendDeferral = null; }); }