Erstellen und Registrieren einer Hintergrundaufgabe außerhalb von Prozessen

Wichtige APIs

Erstellen Sie eine Hintergrundaufgabenklasse, und registrieren Sie diese für die Ausführung, wenn sich die App nicht im Vordergrund befindet. In diesem Thema wird gezeigt, wie Sie eine Hintergrundaufgabe erstellen und registrieren, die in einem vom App-Prozess getrennten Prozess ausgeführt wird. Informationen zum Ausführen von Hintergrundarbeiten direkt in der Vordergrundanwendung finden Sie unter Erstellen und Registrieren einer In-Process-Hintergrundaufgabe.

Hinweis

Wenn Sie eine Hintergrundaufgabe zur Medienwiedergabe im Hintergrund verwenden, finden Sie unter Wiedergeben von Medien im Hintergrund Informationen zu Verbesserungen in Windows 10, Version 1607, die dies erleichtern.

Hinweis

Wenn Sie eine Out-of-Process-Hintergrundaufgabe in einer C#-Desktopanwendung mit .NET 6 oder höher implementieren, verwenden Sie die C#/WinRT-Dokumenterstellungsunterstützung, um eine Windows-Runtime Komponente zu erstellen. Dies gilt für Apps, die die Windows App SDK, WinUI 3, WPF oder WinForms verwenden. Ein Beispiel für eine Hintergrundaufgabe finden Sie unter " Hintergrundaufgaben" .

Erstellen einer Hintergrundaufgabenklasse

Sie können Code im Hintergrund ausführen, indem Sie Klassen schreiben, die die IBackgroundTask-Schnittstelle implementieren. Dieser Code wird ausgeführt, wenn ein bestimmtes Ereignis mithilfe von SystemTrigger oder MaintenanceTrigger ausgelöst wird.

Die folgenden Schritte zeigen, wie Sie eine neue Klasse zum Implementieren der IBackgroundTask-Schnittstelle schreiben.

  1. Erstellen Sie ein neues Projekt für Hintergrundaufgaben, und fügen Sie es zu Ihrer Projektmappe hinzu. Klicken Sie hierzu im Projektmappen-Explorer mit der rechten Maustaste auf Ihren Lösungsknoten, und wählen Sie "Neue Projecthinzufügen"> aus. Wählen Sie dann den projekttyp Windows-Runtime Komponente aus, benennen Sie das Projekt, und klicken Sie auf 'OK'.
  2. Verweisen Sie auf das Hintergrundaufgabenprojekt aus dem Projekt für UWP-Apps (Universelle Windows-Plattform). Klicken Sie für eine C#- oder C++-App in Ihrem App-Projekt mit der rechten Maustaste auf Verweise , und wählen Sie "Neue Referenz hinzufügen" aus. Wählen Sie unter Projektmappe die Option Projekte. Wählen Sie dann den Namen Ihres Hintergrundaufgabenprojekts aus, und klicken Sie auf OK.
  3. Fügen Sie dem Projekt "Hintergrundaufgaben" eine neue Klasse hinzu, die die IBackgroundTask-Schnittstelle implementiert. Die IBackgroundTask.Run-Methode ist ein erforderlicher Einstiegspunkt, der aufgerufen wird, wenn das angegebene Ereignis ausgelöst wird; Diese Methode ist in jeder Hintergrundaufgabe erforderlich.

Hinweis

Die Hintergrundaufgabenklasse selbst und alle anderen Klassen im Hintergrundaufgabenprojekt müssen öffentliche Klassen sein, die versiegelt (oder endgültig) sind.

Der folgende Beispielcode zeigt einen sehr einfachen Ausgangspunkt für eine Hintergrundaufgabenklasse.

// ExampleBackgroundTask.cs
using Windows.ApplicationModel.Background;

namespace Tasks
{
    public sealed class ExampleBackgroundTask : IBackgroundTask
    {
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            
        }        
    }
}
// First, add ExampleBackgroundTask.idl, and then build.
// ExampleBackgroundTask.idl
namespace Tasks
{
    [default_interface]
    runtimeclass ExampleBackgroundTask : Windows.ApplicationModel.Background.IBackgroundTask
    {
        ExampleBackgroundTask();
    }
}

// ExampleBackgroundTask.h
#pragma once

#include "ExampleBackgroundTask.g.h"

namespace winrt::Tasks::implementation
{
    struct ExampleBackgroundTask : ExampleBackgroundTaskT<ExampleBackgroundTask>
    {
        ExampleBackgroundTask() = default;

        void Run(Windows::ApplicationModel::Background::IBackgroundTaskInstance const& taskInstance);
    };
}

namespace winrt::Tasks::factory_implementation
{
    struct ExampleBackgroundTask : ExampleBackgroundTaskT<ExampleBackgroundTask, implementation::ExampleBackgroundTask>
    {
    };
}

// ExampleBackgroundTask.cpp
#include "pch.h"
#include "ExampleBackgroundTask.h"

namespace winrt::Tasks::implementation
{
    void ExampleBackgroundTask::Run(Windows::ApplicationModel::Background::IBackgroundTaskInstance const& taskInstance)
    {
        throw hresult_not_implemented();
    }
}
// ExampleBackgroundTask.h
#pragma once

using namespace Windows::ApplicationModel::Background;

namespace Tasks
{
    public ref class ExampleBackgroundTask sealed : public IBackgroundTask
    {

    public:
        ExampleBackgroundTask();

        virtual void Run(IBackgroundTaskInstance^ taskInstance);
        void OnCompleted(
            BackgroundTaskRegistration^ task,
            BackgroundTaskCompletedEventArgs^ args
        );
    };
}

// ExampleBackgroundTask.cpp
#include "ExampleBackgroundTask.h"

using namespace Tasks;

void ExampleBackgroundTask::Run(IBackgroundTaskInstance^ taskInstance)
{
}
  1. Wenn asynchroner Code in der Hintergrundaufgabe ausgeführt wird, muss in der Hintergrundaufgabe eine Verzögerung verwendet werden. Wenn Sie keine Verzögerung verwenden, kann der Hintergrundaufgabenprozess unerwartet beendet werden, wenn die Run-Methode zurückgibt, bevor eine asynchrone Arbeit abgeschlossen wurde.

Fordern Sie die Verzögerung in der Run-Methode an, bevor Sie die asynchrone Methode aufrufen. Speichern Sie die Verzögerung auf ein Klassendatenelement, damit sie über die asynchrone Methode zugegriffen werden kann. Deklarieren Sie das Objekt so, dass die Verzögerung nach Abschluss des asynchronen Codes abgeschlossen wird.

Der folgende Beispielcode ruft die Verzögerung ab, speichert sie und gibt sie frei, wenn der asynchrone Code abgeschlossen ist.

BackgroundTaskDeferral _deferral; // Note: defined at class scope so that we can mark it complete inside the OnCancel() callback if we choose to support cancellation
public async void Run(IBackgroundTaskInstance taskInstance)
{
    _deferral = taskInstance.GetDeferral();
    //
    // TODO: Insert code to start one or more asynchronous methods using the
    //       await keyword, for example:
    //
    // await ExampleMethodAsync();
    //

    _deferral.Complete();
}
// ExampleBackgroundTask.h
...
private:
    Windows::ApplicationModel::Background::BackgroundTaskDeferral m_deferral{ nullptr };

// ExampleBackgroundTask.cpp
...
Windows::Foundation::IAsyncAction ExampleBackgroundTask::Run(
    Windows::ApplicationModel::Background::IBackgroundTaskInstance const& taskInstance)
{
    m_deferral = taskInstance.GetDeferral(); // Note: defined at class scope so that we can mark it complete inside the OnCancel() callback if we choose to support cancellation.
    // TODO: Modify the following line of code to call a real async function.
    co_await ExampleCoroutineAsync(); // Run returns at this point, and resumes when ExampleCoroutineAsync completes.
    m_deferral.Complete();
}
void ExampleBackgroundTask::Run(IBackgroundTaskInstance^ taskInstance)
{
    m_deferral = taskInstance->GetDeferral(); // Note: defined at class scope so that we can mark it complete inside the OnCancel() callback if we choose to support cancellation.

    //
    // TODO: Modify the following line of code to call a real async function.
    //       Note that the task<void> return type applies only to async
    //       actions. If you need to call an async operation instead, replace
    //       task<void> with the correct return type.
    //
    task<void> myTask(ExampleFunctionAsync());

    myTask.then([=]() {
        m_deferral->Complete();
    });
}

Hinweis

In C# werden asynchrone Methoden für Hintergrundaufgaben mithilfe der Schlagwörter async/await aufgerufen. In C++/CX kann ein ähnliches Ergebnis mithilfe einer Taskchain erzielt werden.

Weitere Informationen zu asynchronen Mustern finden Sie unter Asynchrone Programmierung. Weitere Beispiele zum Verhindern der vorzeitigen Beendigung einer Hintergrundaufgabe mithilfe von Verzögerungen finden Sie im Beispiel zu Hintergrundaufgaben.

Die folgenden Schritte werden in einer Ihrer App-Klassen durchgeführt (beispielsweise in "MainPage.xaml.cs").

Hinweis

Sie können auch eine Funktion zum Registrieren von Hintergrundaufgaben erstellen – siehe Registrieren einer Hintergrundaufgabe. In diesem Fall können Sie anstelle der nächsten drei Schritte einfach den Trigger erstellen und der Registrierungsfunktion zusammen mit dem Aufgabennamen, dem Aufgabeneintragspunkt und (optional) einer Bedingung bereitstellen.

Registrieren der auszuführenden Hintergrundaufgabe

  1. Erfahren Sie, ob die Hintergrundaufgabe bereits registriert ist, indem Sie die BackgroundTaskRegistration.AllTasks-Eigenschaft durchlaufen. Dieser Schritt ist sehr wichtig. Sollte Ihre App nicht überprüfen, ob Hintergrundaufgaberegistrierungen vorhanden sind, könnte es passieren, dass sie die Aufgabe mehrere Male registriert, was zu Leistungseinbrüchen führt und die verfügbare CPU-Zeit der Aufgabe maximiert, bevor die Arbeit abgeschlossen werden kann.

Im folgenden Beispiel wird die AllTasks-Eigenschaft durchläuft und eine Flagvariable auf "true" festgelegt, wenn die Aufgabe bereits registriert ist.

var taskRegistered = false;
var exampleTaskName = "ExampleBackgroundTask";

foreach (var task in BackgroundTaskRegistration.AllTasks)
{
    if (task.Value.Name == exampleTaskName)
    {
        taskRegistered = true;
        break;
    }
}
std::wstring exampleTaskName{ L"ExampleBackgroundTask" };

auto allTasks{ Windows::ApplicationModel::Background::BackgroundTaskRegistration::AllTasks() };

bool taskRegistered{ false };
for (auto const& task : allTasks)
{
    if (task.Value().Name() == exampleTaskName)
    {
        taskRegistered = true;
        break;
    }
}

// The code in the next step goes here.
boolean taskRegistered = false;
Platform::String^ exampleTaskName = "ExampleBackgroundTask";

auto iter = BackgroundTaskRegistration::AllTasks->First();
auto hascur = iter->HasCurrent;

while (hascur)
{
    auto cur = iter->Current->Value;

    if(cur->Name == exampleTaskName)
    {
        taskRegistered = true;
        break;
    }

    hascur = iter->MoveNext();
}
  1. Wenn die Hintergrundaufgabe noch nicht registriert ist, verwenden Sie BackgroundTaskBuilder, um eine Instanz Ihrer Hintergrundaufgabe zu generieren. Bei dem Einstiegspunkt der Aufgabe sollte es sich um den Namen der Hintergrundaufgabenklasse mit dem Namespace als Präfix handeln.

Der Hintergrundaufgabenauslöser bestimmt, ob die Hintergrundaufgabe ausgeführt wird. Eine Liste mit möglichen Auslösern erhalten Sie unter SystemTrigger.

In diesem Code wird beispielsweise eine neue Hintergrundaufgabe erstellt und festgelegt, dass diese ausgeführt wird, wenn der TimeZoneChanged-Trigger auftritt:

var builder = new BackgroundTaskBuilder();

builder.Name = exampleTaskName;
builder.TaskEntryPoint = "Tasks.ExampleBackgroundTask";
builder.SetTrigger(new SystemTrigger(SystemTriggerType.TimeZoneChange, false));
if (!taskRegistered)
{
    Windows::ApplicationModel::Background::BackgroundTaskBuilder builder;
    builder.Name(exampleTaskName);
    builder.TaskEntryPoint(L"Tasks.ExampleBackgroundTask");
    builder.SetTrigger(Windows::ApplicationModel::Background::SystemTrigger{
        Windows::ApplicationModel::Background::SystemTriggerType::TimeZoneChange, false });
    // The code in the next step goes here.
}
auto builder = ref new BackgroundTaskBuilder();

builder->Name = exampleTaskName;
builder->TaskEntryPoint = "Tasks.ExampleBackgroundTask";
builder->SetTrigger(ref new SystemTrigger(SystemTriggerType::TimeZoneChange, false));
  1. Sie können eine Bedingung hinzufügen, die bestimmt, wann Ihre Aufgabe ausgeführt wird, nachdem das Auslöseereignis eintritt (optional). Wenn Sie zum Beispiel möchten, dass die Aufgabe erst ausgeführt wird, wenn der Benutzer anwesend ist, verwenden Sie die Bedingung UserPresent. Eine Liste mit möglichen Bedingungen finden Sie in SystemConditionType.

Der folgende Beispielcode weist eine Bedingung zu, die die Anwesenheit des Benutzers voraussetzt:

builder.AddCondition(new SystemCondition(SystemConditionType.UserPresent));
builder.AddCondition(Windows::ApplicationModel::Background::SystemCondition{ Windows::ApplicationModel::Background::SystemConditionType::UserPresent });
// The code in the next step goes here.
builder->AddCondition(ref new SystemCondition(SystemConditionType::UserPresent));
  1. Registrieren Sie die Hintergrundaufgabe, indem Sie die Register-Methode für das BackgroundTaskBuilder-Objekt aufrufen. Speichern Sie das BackgroundTaskRegistration-Ergebnis, sodass es im nächsten Schritt verwendet werden kann.

Der folgende Code registriert die Hintergrundaufgabe und speichert das Ergebnis:

BackgroundTaskRegistration task = builder.Register();
Windows::ApplicationModel::Background::BackgroundTaskRegistration task{ builder.Register() };
BackgroundTaskRegistration^ task = builder->Register();

Hinweis

Universelle Windows-Apps müssen jedoch RequestAccessAsync aufrufen, bevor Hintergrundtrigger-Typen registriert werden.

Verwenden Sie den ServicingComplete-Trigger (siehe SystemTriggerType) zum Ausführen von Konfigurationsänderungen nach dem Update wie Migrieren der Datenbank der App und Registrieren von Hintergrundaufgaben, um sicherzustellen, dass Ihre universelle Windows-App nach der Veröffentlichung eines Updates weiterhin ordnungsgemäß ausgeführt wird. Es empfiehlt sich, die Registrierung von Hintergrundaufgaben im Zusammenhang mit der vorherigen Version der App aufzuheben (siehe RemoveAccess) und die Hintergrundaufgaben für die neue Version der App zu registrieren (siehe RequestAccessAsync).

Weitere Informationen finden Sie unter Richtlinien für Hintergrundaufgaben.

Behandeln des Abschlusses der Hintergrundaufgabe mithilfe von Ereignishandlern

Sie sollten eine Methode mit dem BackgroundTaskCompletedEventHandler-Element registrieren, damit Ihre App Ergebnisse von der Hintergrundaufgabe abrufen kann. Wenn die App gestartet oder fortgesetzt wird, wird die markierte Methode aufgerufen, wenn die Hintergrundaufgabe seit der letzten Ausführung der App im Vordergrund abgeschlossen wurde. (Die OnCompleted-Methode wird sofort aufgerufen, wenn die Hintergrundaufgabe abgeschlossen wird, während sich Ihre App im Vordergrund befindet.)

  1. Schreiben Sie eine OnCompleted-Methode, um den Abschluss von Hintergrundaufgaben zu behandeln. Das Ergebnis der Hintergrundaufgabe kann z. B. eine Aktualisierung der Benutzeroberfläche auslösen. Das hier gezeigte Methodenprofil ist für die OnCompleted-Ereignishandlermethode erforderlich, obwohl dieses Beispiel nicht den args-Parameter verwendet.

Der folgende Beispielcode erkennt den Abschluss der Hintergrundaufgabe und ruft eine Beispielmethode zur Aktualisierung der Benutzeroberfläche auf, die eine Meldungszeichenfolge erfordert.

private void OnCompleted(IBackgroundTaskRegistration task, BackgroundTaskCompletedEventArgs args)
{
    var settings = Windows.Storage.ApplicationData.Current.LocalSettings;
    var key = task.TaskId.ToString();
    var message = settings.Values[key].ToString();
    UpdateUI(message);
}
void UpdateUI(winrt::hstring const& message)
{
    MyTextBlock().Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [=]()
    {
        MyTextBlock().Text(message);
    });
}

void OnCompleted(
    Windows::ApplicationModel::Background::BackgroundTaskRegistration const& sender,
    Windows::ApplicationModel::Background::BackgroundTaskCompletedEventArgs const& /* args */)
{
	// You'll previously have inserted this key into local settings.
    auto settings{ Windows::Storage::ApplicationData::Current().LocalSettings().Values() };
    auto key{ winrt::to_hstring(sender.TaskId()) };
    auto message{ winrt::unbox_value<winrt::hstring>(settings.Lookup(key)) };

    UpdateUI(message);
}
void MainPage::OnCompleted(BackgroundTaskRegistration^ task, BackgroundTaskCompletedEventArgs^ args)
{
    auto settings = ApplicationData::Current->LocalSettings->Values;
    auto key = task->TaskId.ToString();
    auto message = dynamic_cast<String^>(settings->Lookup(key));
    UpdateUI(message);
}

Hinweis

Aktualisierungen der Benutzeroberfläche sollten asynchron durchgeführt werden, um den Benutzeroberflächenthread nicht zu blockieren. Ein Beispiel dazu finden Sie in der UpdateUI-Methode im Beispiel für eine Hintergrundaufgabe.

  1. Gehen Sie dorthin zurück, wo Sie die Hintergrundaufgabe registriert haben. Fügen Sie nach dieser Codezeile ein neues BackgroundTaskCompletedEventHandler-Objekt hinzu. Stellen Sie Ihre OnCompleted-Methode als Parameter für den BackgroundTaskCompletedEventHandler-Konstruktor zur Verfügung.

Der folgende Beispielcode fügt dem BackgroundTaskRegistration-Element ein BackgroundTaskCompletedEventHandler-Element hinzu:

task.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);
task.Completed({ this, &MainPage::OnCompleted });
task->Completed += ref new BackgroundTaskCompletedEventHandler(this, &MainPage::OnCompleted);

Deklarieren Sie im App-Manifest, dass Ihre App Hintergrundaufgaben verwendet

Bevor Ihre App Hintergrundaufgaben ausführen kann, müssen Sie alle Hintergrundaufgaben im App-Manifest deklarieren. Wenn Ihre App versucht, eine Hintergrundaufgabe mit einem Trigger zu registrieren, der nicht im Manifest aufgeführt ist, schlägt die Registrierung der Hintergrundaufgabe mit einem Fehler "Laufzeitklasse nicht registriert" fehl.

  1. Öffnen Sie den Paketmanifest-Designer durch Öffnen der Datei namens „Package.appxmanifest“.
  2. Öffnen Sie die Registerkarte Deklarationen.
  3. Wählen Sie in der Dropdownliste Verfügbare Deklarationen die Option Hintergrundaufgaben aus, und klicken Sie auf Hinzufügen.
  4. Aktivieren Sie das Kontrollkästchen Systemereignis.
  5. Geben Sie im Einstiegspunkt: Textfeld den Namespace und den Namen Ihrer Hintergrundklasse ein, die für dieses Beispiel "Tasks.ExampleBackgroundTask" steht.
  6. Schließen Sie den Manifest-Designer.

Das folgende Erweiterungselement wird zur Datei „Package.appxmanifest“ hinzugefügt, um die Hintergrundaufgabe zu registrieren:

<Extensions>
  <Extension Category="windows.backgroundTasks" EntryPoint="Tasks.ExampleBackgroundTask">
    <BackgroundTasks>
      <Task Type="systemEvent" />
    </BackgroundTasks>
  </Extension>
</Extensions>

Zusammenfassung und nächste Schritte

Sie sollten jetzt über die Grundlagen verfügen, um eine Hintergrundaufgabenklasse zu schreiben, die Hintergrundaufgabe in Ihrer App zu registrieren und Ihre App so zu konfigurieren, dass Sie den Abschluss der Hintergrundaufgabe erkennt. Sie sollten auch mit der Aktualisierung des Anwendungsmanifests vertraut sein, damit Ihre App die Hintergrundaufgabe erfolgreich registrieren kann.

Hinweis

Laden Sie das Beispiel für eine Hintergrundaufgabe herunter, um ähnliche Codebeispiele im Kontext einer vollständigen und stabilen UWP-App (Universelle Windows-Plattform) mit Hintergrundaufgaben zu erhalten.

Eine API-Referenz, konzeptionelle Richtlinien zu Hintergrundaufgaben und ausführlichere Anweisungen zum Schreiben von Apps, die Hintergrundaufgaben verwenden, finden Sie unter den folgenden verwandten Themen:

Ausführliche Themen mit Anweisungen zu Hintergrundaufgaben

Ratschläge zu Hintergrundaufgaben

Hintergrundaufgabe – API-Referenz