通过应用生命周期 API 管理电源

Windows 应用 SDK 中的应用生命周期 API 在 Microsoft.Windows.System.Power 命名空间中提供了一组电源管理 API。 可以通过这些 API 了解应用如何影响设备的电源状态,使应用能够做出有关资源使用情况的智能决策。 例如,当设备使用电池电源运行时,应用可以使用此 API 推迟资源密集型后台任务。

电源管理 API 使用基于回调的模型,该模型类似于现有的 PowerSettingRegisterNotification 函数。 使用回调模型会将 API 的覆盖范围扩展到所有应用,包括后台应用、无外设应用和其他应用。

先决条件

若要在 Windows 应用 SDK 中使用应用生命周期 API,请执行以下操作:

  1. 下载并安装 Windows 应用 SDK 的最新版本。 有关详细信息,请参阅安装适用于 Windows 应用 SDK 的工具
  2. 按照说明创建你的第一个 WinUI 3 项目,或者在现有项目中使用 Windows App SDK

订阅和响应事件

下面的示例演示如何订阅和响应 PowerManager 事件。 此代码会在启动过程中订阅 BatteryStatusChanged 事件。 然后,应用会通过检查当前的功率级别并相应地调整其资源使用情况来响应更改。 例如,如果电池处于低功耗状态,则应用可能会延迟任何非关键后台工作。

注意

应用可以随时针对这些事件进行注册和注销操作,但大多数应用都需要在 WinMain 中设置回调(只要应用继续运行,回调就会持续存在)。

BOOL bWorkInProgress;
winrt::event_token batteryToken;
winrt::event_token powerToken;
winrt::event_token powerSourceToken;
winrt::event_token chargeToken;
winrt::event_token dischargeToken;

void RegisterPowerManagerCallbacks()
{
    batteryToken = PowerManager::BatteryStatusChanged([&](
        const auto&, winrt::Windows::Foundation::IInspectable obj) { OnBatteryStatusChanged(); });
    powerToken = PowerManager::PowerSupplyStatusChanged([&](
        const auto&, winrt::Windows::Foundation::IInspectable obj) { OnPowerSupplyStatusChanged(); });
    powerSourceToken = PowerManager::PowerSourceKindChanged([&](
        const auto&, winrt::Windows::Foundation::IInspectable obj) { OnPowerSourceKindChanged(); });
    chargeToken = PowerManager::RemainingChargePercentChanged([&](
        const auto&, winrt::Windows::Foundation::IInspectable obj) { OnRemainingChargePercentChanged(); });
    dischargeToken = PowerManager::RemainingDischargeTimeChanged([&](
        const auto&, winrt::Windows::Foundation::IInspectable obj) { OnRemainingDischargeTimeChanged(); });

    if (batteryToken && powerToken && powerSourceToken && chargeToken && dischargeToken)
    {
        OutputMessage(L"Successfully registered for state notifications");
    }
    else
    {
        OutputMessage(L"Failed to register for state notifications");
    }
}

void OnBatteryStatusChanged()
{
    const size_t statusSize = 16;
    WCHAR szStatus[statusSize];
    wmemset(&(szStatus[0]), 0, statusSize);

    BatteryStatus batteryStatus = PowerManager::BatteryStatus();
    int remainingCharge = PowerManager::RemainingChargePercent();
    switch (batteryStatus)
    {
    case BatteryStatus::Charging:
        wcscpy_s(szStatus, L"Charging");
        break;
    case BatteryStatus::Discharging:
        wcscpy_s(szStatus, L"Discharging");
        break;
    case BatteryStatus::Idle:
        wcscpy_s(szStatus, L"Idle");
        break;
    case BatteryStatus::NotPresent:
        wcscpy_s(szStatus, L"NotPresent");
        break;
    }

    OutputFormattedMessage(
        L"Battery status changed: %s, %d%% remaining", 
        szStatus, remainingCharge);
    DetermineWorkloads();
}

void OnPowerSupplyStatusChanged()
{
//...etc
}

根据多个状态值配置应用逻辑

PowerManager 事件属于相对较低的级别,在某些情况下,调用单个事件处理程序可能无法为应用提供足够的信息来决定如何表现。 在此示例中,当设备断开与电源的连接时,可以调用 PowerSupplyStatusChanged 事件。 在这种情况下,应用必须在确定如何继续之前检查当前电池状态。

void DetermineWorkloads()
{
    BatteryStatus batteryStatus = PowerManager::BatteryStatus();
    int remainingCharge = PowerManager::RemainingChargePercent();
    PowerSupplyStatus powerStatus = PowerManager::PowerSupplyStatus();
    PowerSourceKind powerSource = PowerManager::PowerSourceKind();

    if ((powerSource == PowerSourceKind::DC 
        && batteryStatus == BatteryStatus::Discharging 
        && remainingCharge < 25)
        || (powerSource == PowerSourceKind::AC
        && powerStatus == PowerSupplyStatus::Inadequate))
    {
        // The device is not in a good battery/power state, 
        // so we should pause any non-critical work.
        PauseNonCriticalWork();
    }
    else if ((batteryStatus != BatteryStatus::Discharging && remainingCharge > 75)
        && powerStatus != PowerSupplyStatus::Inadequate)
    {
        // The device is in good battery/power state,
        // so let's kick of some high-power work.
        StartPowerIntensiveWork();
    }
}

检查屏幕状态

可以通过 PowerManager 类了解与应用的电源使用情况相关的其他设备状态。 例如,当设备的显示器关闭时,应用可以禁用图形处理。

void OnDisplayStatusChanged()
{
    const size_t statusSize = 16;
    WCHAR szStatus[statusSize];
    wmemset(&(szStatus[0]), 0, statusSize);

    DisplayStatus displayStatus = PowerManager::DisplayStatus();
    switch (displayStatus)
    {
    case DisplayStatus::Dimmed:
        wcscpy_s(szStatus, L"Dimmed");
        break;
    case DisplayStatus::Off:
        wcscpy_s(szStatus, L"Off");
        break;
    case DisplayStatus::On:
        wcscpy_s(szStatus, L"On");
        break;
    }

    OutputFormattedMessage(
        L"Display status changed: %s", szStatus);
    if (displayStatus == DisplayStatus::Off)
    {
        // The screen is off, let's stop rendering foreground graphics,
        // and instead kick off some background work now.
        StopUpdatingGraphics();
        StartDoingBackgroundWork();
    }
}

取消订阅事件

在生命周期内,应用可以注册和取消注册通知。 如果应用不需要在整个生命周期内接收电源状态通知,请使用语言的首选事件注册管理系统。

void UnregisterPowerManagerCallbacks()
{
    OutputMessage(L"Unregistering state notifications");
    PowerManager::BatteryStatusChanged(batteryToken);
    PowerManager::PowerSupplyStatusChanged(powerToken);
    PowerManager::PowerSourceKindChanged(powerSourceToken);
    PowerManager::RemainingChargePercentChanged(chargeToken);
    PowerManager::RemainingDischargeTimeChanged(dischargeToken);
}