Gerenciamento de energia com API de ciclo de vida do aplicativo

A API do ciclo de vida do aplicativo no SDK do Aplicativo Windows fornece um conjunto de APIs de gerenciamento de energia no namespace Microsoft.Windows.System.Power. Essas APIs dão visibilidade de como o aplicativo afeta o estado de energia do dispositivo e habilitam o aplicativo para tomar decisões inteligentes sobre o uso de recursos. Por exemplo, um aplicativo pode usar essa API para adiar tarefas no segundo plano com uso intensivo de recursos enquanto o dispositivo estiver sendo executado com energia da bateria.

As APIs de gerenciamento de energia usam um modelo com base em retorno de chamada parecido com a função existente PowerSettingRegisterNotification. O uso de um modelo de retorno de chamada estende o alcance da API a todos os aplicativos, incluindo aplicativos no segundo plano, aplicativos sem periféricos e outros.

Pré-requisitos

Para usar a API do ciclo de vida do aplicativo no SDK do Aplicativo Windows:

  1. Baixe e instale a versão experimental mais recente do SDK de Aplicativo Windows. Para obter mais informações, confira Instalar ferramentas para o SDK do Aplicativo Windows.
  2. Siga as instruções para Criar seu primeiro projeto da WinUI 3 ou Usar o SDK do Aplicativo Windows em um projeto existente.

Inscreva-se e responda a eventos

O exemplo a seguir demonstra como se inscrever e responder a eventos do PowerManager. Esse código assina o evento BatteryStatusChanged durante a inicialização. Depois, o aplicativo responde às alterações verificando o nível de energia atual e ajustando o uso de recursos adequadamente. Por exemplo, se a bateria for descarregada em um estado de baixa energia, o aplicativo poderá adiar trabalhos não críticos no segundo plano.

Observação

Os aplicativos podem se registrar e cancelar o registro para esses eventos a qualquer momento, mas a maioria dos aplicativos desejará definir retornos de chamada em WinMain que persistam enquanto o aplicativo continuar a ser executado.

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
}

Configurar a lógica do aplicativo com base em diversos valores de status

Eventos do PowerManager têm nível relativamente baixo e, em alguns casos, um único manipulador de eventos sendo chamado pode não fornecer informações suficientes para o aplicativo decidir como se comportar. Neste exemplo, o evento PowerSupplyStatusChanged pode ser chamado quando o dispositivo for desconectado da energia. Nesse caso, o aplicativo precisa verificar o status atual da bateria antes de decidir como proceder.

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

Verificar status da tela

A classe PowerManager traz informações sobre outros estados de dispositivo relevantes para o uso de energia de um aplicativo. Por exemplo, os aplicativos podem desativar o processamento de gráficos quando a tela do dispositivo estiver desativada.

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

Cancelar a assinatura de eventos

Os aplicativos podem registrar e cancelar o registro de notificações durante o ciclo de vida. Use o sistema de gerenciamento de registro de eventos preferido do seu idioma, caso o seu aplicativo não precise receber notificações de status de energia durante todo o ciclo de vida.

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