Energieverwaltung mit der API für den Lebenszyklus von Anwendungen

Die App Lifecycle API im Windows App SDK bietet eine Reihe von Energieverwaltungs-APIs im Microsoft.Windows.System.Power Namespace. Diese APIs geben Aufschluss darüber, wie sich eine App auf den Energiestatus des Geräts auswirkt, und ermöglichen es der App, intelligente Entscheidungen über die Ressourcennutzung zu treffen. Eine Anwendung könnte diese API beispielsweise nutzen, um ressourcenintensive Hintergrundaufgaben zu verschieben, während das Gerät im Akkubetrieb läuft.

Die Energieverwaltungs-APIs verwenden ein callback-basiertes Modell, das der bestehenden Funktion PowerSettingRegisterNotification ähnelt. Die Verwendung eines Rückrufmodells erweitert die Reichweite der API auf alle Anwendungen, einschließlich Hintergrundanwendungen, Headless-Apps und andere.

Voraussetzungen

So verwenden Sie die App Lifecycle API im Windows App SDK:

  1. Laden Sie das neueste experimentelle Release des Windows App SDK herunter und installieren Sie es. Weitere Informationen finden Sie unter Installieren von Tools für das Windows App SDK.
  2. Befolgen Sie die Anweisungen zum Erstellen Ihres ersten WinUI 3-Projekts oder zum Verwenden des Windows App SDK in einem vorhandenen Projekt.

Abonnieren und Reagieren auf Ereignisse

Das folgende Beispiel zeigt, wie man PowerManager-Ereignisse abonniert und auf sie reagiert. Dieser Code abonniert das Ereignis BatteryStatusChanged während des Starts. Die App reagiert dann auf Änderungen, indem sie den aktuellen Stromverbrauch prüft und den Ressourcenverbrauch entsprechend anpasst. Wenn sich beispielsweise der Akku bei niedrigem Stromverbrauch entlädt, kann die App alle nicht kritischen Hintergrundarbeiten zurückstellen.

Hinweis

Apps können sich jederzeit für diese Ereignisse registrieren und wieder abmelden, aber die meisten Apps werden Rückrufe in WinMain festlegen wollen, die so lange bestehen bleiben, wie die App läuft.

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
}

Konfigurieren Sie die Anwendungslogik basierend auf mehreren Statuswerten

Die Ereignisse von PowerManager sind relativ niedrigschwellig, und in manchen Szenarien liefert ein einziger Ereignis-Handler, der aufgerufen wird, möglicherweise nicht genügend Informationen, damit die Anwendung entscheiden kann, wie sie sich verhalten soll. In diesem Beispiel könnte das Ereignis PowerSupplyStatusChanged aufgerufen werden, wenn das Gerät von der Stromversorgung getrennt wird. In diesem Fall muss die App den aktuellen Batteriestatus prüfen, bevor sie entscheidet, wie sie weiter vorgeht.

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

Bildschirmstatus prüfen

Die Klasse PowerManager bietet Informationen über andere Gerätezustände, die für den Stromverbrauch einer App relevant sind. So können Anwendungen beispielsweise die Grafikverarbeitung deaktivieren, wenn der Bildschirm des Geräts ausgeschaltet ist.

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

Abbestellen von Ereignissen

Apps können sich während ihres Lebenszyklus für Benachrichtigungen registrieren und abmelden. Verwenden Sie das bevorzugte Verwaltungssystem für die Ereignisregistrierung in Ihrer Sprache, wenn Ihre Anwendung nicht während ihres gesamten Lebenszyklus Benachrichtigungen über den Energiestatus erhalten muss.

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