Управление питанием с помощью API жизненного цикла приложения

API жизненного цикла приложения в пакете SDK для приложений Windows предоставляет набор API управления питанием в пространстве имен Microsoft.Windows.System.Power . Эти API обеспечивают видимость того, как приложение влияет на состояние питания устройства, и они позволяют приложению принимать интеллектуальные решения об использовании ресурсов. Например, приложение может использовать этот API для отсрочки ресурсоемких фоновых задач, пока устройство работает на батарее.

API управления питанием используют модель обратного вызова, аналогичную существующей функции PowerSettingRegisterNotification . Использование модели обратного вызова расширяет доступ API ко всем приложениям, включая фоновые приложения, без головные приложения и другие.

Необходимые компоненты

Чтобы использовать API жизненного цикла приложения в пакете SDK для приложений Для Windows:

  1. Скачайте и установите последнюю версию пакета SDK для приложений Windows. Дополнительные сведения см. в статье Установка инструментов для Windows App SDK.
  2. Выполните инструкции по созданию простого проекта WinUI 3 или применению пакета SDK для приложений Windows в существующем проекте.

Подписка и реагирование на события

В следующем примере показано, как подписаться на события 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);
}