Поделиться через


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

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

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

Предварительные условия

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

  1. Скачайте и установите последний выпуск Windows App SDK. Подробности смотрите в разделе Начало работы с WinUI 3.
  2. Следуйте инструкциям, чтобы Создать ваш первый проект WinUI или использовать 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);
}