Postpone app suspension with extended execution

通过延续运行(Extended Execution),应用可以在最小化或者锁屏的时候运行。

通常进入幕后(最小化或者锁屏)的时候,App会被挂起,内存会保留但是代码不会运行。但是这不会里面发生,操作系统可以让App在后台运行一段时间再挂起,或者应用可以申请延续运行一段时间,然后才挂起。

调试模式下不会挂起

创建ExtendedExecutionSession来获取更多后台执行时间。ExtendedExecutionSession有几种会话类型:

  • Unspecified
  • LocationTracking
  • SavingData

一次只能申请一个ExtendedExecutionSession。Store不允许App使用ExtendedExecutionForegroundSession或者ExtendedExecutionForegroundReason;

<! – Run while minimized –>

使用ExtendedExecutionSession的时机:

  • 任何时刻,只要应用在前台运行
  • 当App接收到挂起事件的时候

两种情况下代码相同。但是第一种情况App申请成功之后就不会收到挂起事件了。第二种情况只是推迟了挂起的发生而已,当时间结束时候会被直接挂起。

使用ExtendedExecutionReason.Unspecified来在应用进入幕后之前获取更多在幕后的运行时间。在桌面版本,这可以有效地阻止应用在最小化地时候被挂起。

ExtendedExecutionReason.Unspecified在插电地情况下可以无限运行,在使用电池地情况下可以运行10分钟。

平板或者笔记本可以开启 Allow the app to run background tasks选项(Settings > System > Battery > Battery usage by App),来获取和桌面类似地效果。

在所有地操作系统上,当设备进入Connected Standby,延续运行也会被暂停。在桌面环境下,锁屏是依然可以延续运行,当屏幕熄灭时进入Connected Standby。在XBox情况下,Connected Standby一般需要等待一个小时才会进入。

ExtendedExecutionReason.LocationTracking 跟GeoLocator相关。

使用ExtendedExecutionReason.SavingData来保存尚未保存地数据,而不是其他目的。

ExtendedExecutionReason.SavingData可以在前台、幕后或者即将挂起地时候申请。在挂起前申请ExtendedExecutionReason.SavingData需要注意地是,当用户再次加载该App地时候,需要等待之前地ExtendedExecutionReason.SavingData完成。

针对延续运行,有三种操作:请求,释放,中止。

请求的例子:

var newSession = new ExtendedExecutionSession();
newSession.Reason = ExtendedExecutionReason.Unspecified;
newSession.Revoked += SessionRevoked;
ExtendedExecutionResult result = await newSession.RequestExtensionAsync();

switch (result)
{
    case ExtendedExecutionResult.Allowed:
        DoLongRunningWork();
        break;

    default:
    case ExtendedExecutionResult.Denied:
        DoShortRunningWork();
        break;
}

用户设置可能会影响延续运行: 参考Background Activity and Energy Awareness

当延续运行的许可时间截止、或者其他前台任务需要资源的时候,延续运行可能会被释放,App会接受到一个Revoked事件。

在ExtendedExecutionReason.SavingData ,App只有1秒钟时间来在挂起前完成操作。

一个例子:

private async void SessionRevoked(object sender, ExtendedExecutionRevokedEventArgs args)
{
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        switch (args.Reason)
        {
            case ExtendedExecutionRevokedReason.Resumed:
                rootPage.NotifyUser("Extended execution revoked due to returning to foreground.", NotifyType.StatusMessage);
                break;

            case ExtendedExecutionRevokedReason.SystemPolicy:
                rootPage.NotifyUser("Extended execution revoked due to system policy.", NotifyType.StatusMessage);
                break;
        }

        EndExtendedExecution();
    });
}

App可以主动中止延续运行。允许系统回收资源,一个例子:

void ClearExtendedExecution(ExtendedExecutionSession session)
{
    if (session != null)
    {
        session.Revoked -= SessionRevoked;
        session.Dispose();
        session = null;
    }
}

在中止延续允许之前,确保所有相关的异步操作都结束了。章节中·举了一个相关的例子。

为了良好使用资源,确保App不使用过多内存Memory Management APIs ,以及确保用户没有对BackgroundExecutionManager.RequestAccessAsync 进行限制

(本篇完)