2016-03-19 104 views
18

我无法让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毫秒才能显示出来。这意味着代码将暂停,直到会话结束。

最大的问题是,如果您在未连接调试器的情况下触发此应用程序,启动应用程序,暂停然后恢复,您将看到几秒钟的黑屏,然后操作系统将终止您的应用程序。

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

+0

似乎你不会错过任何东西,但是在文档中找不到任何地方提到“应该在恢复应用程序时触发撤销的事件”。也许你需要在OnResuming中添加一些额外的代码。 –

+0

@MehrzadChehraz否 - 恢复事件似乎只在暂停事件结束后才会被触发。这意味着在发布模式下,由于时间限制,应用程序将被操作系统杀死,并且根本不会升级和恢复事件。 – Romasz

+0

是的你是对的。顺便说一句,你可以添加一个链接或文件说:“恢复应用程序时应该被解雇的事件”? –

回答

1

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

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

看看这个https://msdn.microsoft.com/en-us/magazine/jj991977.aspx的,以获取有关执行如何sheduled

+0

任何想法如何在新线程上执行耗时的操作,并确保将会话保持打开状态直到它结束,而不在UI线程上使用* await *? – Romasz

0

没有UI问题或任何一个很好的洞察力。你的代码有效。你的期望是错误的。

使用​​你告诉你的应用程序,你需要时间来保存,它不会被撤销,直到你完成。在你的情况下,大约需要9秒。

尝试挂起应用程序,等待10秒钟然后撤销它。它会立即发生。 然后尝试暂停应用程序并在会话完成之前撤消它。现在​​会告诉你的操作系统,你的应用程序不能被撤销,它必须等到保存过程完成。那就是你想要的。

Microsoft doc on extended execution

请求一个ExtendedExecutionReason.SavingData扩展执行会话,而应用程序是在悬浮状态创建你应该知道的一个潜在的问题。如果在挂起状态下请求扩展执行会话,并且用户请求应用程序再次启动,则可能需要很长时间才能启动。这是因为扩展执行会话时间段必须在应用程序的旧实例关闭并且可以启动应用程序的新实例之前完成。牺牲启动性能时间是为了保证用户状态不会丢失。

什么在关于“撤销”一节提到的是对你有意思,太:

Revoked事件为ExtendedExecutionReason.SavingData扩展执行会议解雇,该应用程序有一秒钟完成操作它正在执行并完成暂停。

一秒钟是不够的完成你的9秒钟等待。

为了消除延迟显示调试输出的可能性,您可以通过将当前时间添加到输出来对其进行测试。 操作系统可能在会话未正常关闭时出现问题,因为9秒未完成。

还应注意EnterBackground的一句话:

此前的悬浮回调是保存状态后,用户与您的应用程序完成了会议的最佳场所。但是,现在应用程序可能会继续在后台运行,然后由于触发器活动而回到前台而没有达到暂停状态。用户会话之后保存数据的最佳位置是在您输入的后台事件处理程序中。

如果Exiting事件被触发,您可能会想要执行您的代码。

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

UPDATE:

...或者使用Background Task为暂停似乎是结束前的唯一可靠的警告:

// 
// 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(); 
} 

UPDATE2

对于 “适当”应该怎么办,请看official example

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 (e.g., 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; 
    }); 
} 
+0

我仍然没有看到撤销对我的用法 - 现在我可以使用Resuming,LeavingBackground,Launching方法。我期望被撤销的事件在单独的线程上运行,所以我可以将取消令牌传递给我的主要任务或做一些事情。现在它运行在同一个线程上并被阻塞,直到扩展执行完成。 – Romasz

+0

这意味着你必须在不同的线程上使用扩展执行,而不是阻止Suspending方法。由于暂停期望你在几秒钟内完成并且你需要更多的时间,我想这可能会有所帮助。我会从Suspending开始一个后台任务,并在那里使用扩展执行。这样,无论您在保存过程中是否撤销应用程序,它总是(尝试)完成保存。如果数据在应用程序运行时损坏,则应在撤销中止保存过程。 – Neepsnikeep

+0

背景任务是一种不同的方式,并且我认为它对扩展执行没有任何影响。看看我的示例已经在一个新的线程上运行了,什么不应该阻止正常的UI工作。 – Romasz

相关问题