Freigeben über


Erstellen und Registrieren einer Hintergrundaufgabe außerhalb von Prozessen

Wichtige APIs

Erstellen Sie eine Hintergrundaufgabenklasse, und registrieren Sie sie, um sie auszuführen, wenn sich Ihre App nicht im Vordergrund befindet. In diesem Thema wird veranschaulicht, wie Sie eine Hintergrundaufgabe erstellen und registrieren, die in einem separaten Prozess ausgeführt wird als der Prozess Ihrer App. Informationen zum direkten Ausführen von Hintergrundaufgaben in der Vordergrundanwendung finden Sie unter Erstellen und Registrieren einer Hintergrundaufgabe im Prozess.

Hinweis

Wenn Sie eine Hintergrundaufgabe zum Wiedergeben von Medien im Hintergrund verwenden, finden Sie Informationen zu Verbesserungen in Windows 10, Version 1607, unter "Wiedergeben von Medien im Hintergrund ", die es wesentlich einfacher machen.

Hinweis

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

Erstellen der 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 schreiben, die die IBackgroundTask-Schnittstelle implementiert.

  1. Erstellen Sie ein neues Projekt für Hintergrundaufgaben, und fügen Sie es Ihrer Lösung hinzu. Klicken Sie dazu im Projektmappen-Explorer mit der rechten Maustaste auf den Projektmappenknoten, und wählen Sie "Neues Projekt hinzufügen">aus. Wählen Sie dann den Windows-Runtime Komponentenprojekttyp aus, benennen Sie das Projekt, und klicken Sie auf "OK".
  2. Verweisen Sie im Universelle Windows-Plattform-App-Projekt (UWP) auf das Hintergrundaufgabenprojekt. Klicken Sie für eine C#- oder C++-App in Ihrem App-Projekt mit der rechten Maustaste auf Verweise, und wählen Sie "Neuen Verweis hinzufügen" aus. Wählen Sie unter "Projektmappe" "Projekte" und dann den Namen des Hintergrundaufgabenprojekts aus, und klicken Sie auf "OK".
  3. Fügen Sie dem Hintergrundaufgabenprojekt 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 Sie asynchronen Code in Ihrer Hintergrundaufgabe ausführen, muss die Hintergrundaufgabe eine Verzögerung verwenden. Wenn Sie keine Verzögerung verwenden, kann der Hintergrundaufgabenprozess unerwartet beendet werden, wenn die Run-Methode zurückgegeben wird, 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 in einem Klassendatenmemm, sodass über die asynchrone Methode darauf zugegriffen werden kann. Deklarieren Sie die Verzögerung nach Abschluss des asynchronen Codes.

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# können die asynchronen Methoden Ihrer Hintergrundaufgabe mithilfe der asynchronen/await-Schlüsselwörter aufgerufen werden. In C++/CX kann mithilfe einer Aufgabenkette ein ähnliches Ergebnis erzielt werden.

Weitere Informationen zu asynchronen Mustern finden Sie unter "Asynchrone Programmierung". Weitere Beispiele für die Verwendung von Verzögerungsverzögerungen, um zu verhindern, dass eine Hintergrundaufgabe frühzeitig beendet wird, finden Sie im Beispiel für Hintergrundaufgaben.

Die folgenden Schritte werden in einer Ihrer App-Klassen (z. B. MainPage.xaml.cs) ausgeführt.

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 konstruieren und der Registrierungsfunktion zusammen mit dem Aufgabennamen, dem Vorgangseinstiegspunkt und (optional) einer Bedingung bereitstellen.

Registrieren der auszuführenden Hintergrundaufgabe

  1. Ermitteln Sie, ob die Hintergrundaufgabe bereits registriert ist, indem Sie die BackgroundTaskRegistration.AllTasks-Eigenschaft durchlaufen. Dieser Schritt ist wichtig; Wenn Ihre App nicht auf vorhandene Registrierungen von Hintergrundaufgaben überprüft, kann die Aufgabe problemlos mehrmals registriert werden, wodurch Probleme mit der Leistung auftreten und die verfügbare CPU-Zeit der Aufgabe minimiert wird, 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 erstellen. Der Einstiegspunkt für die Aufgabe sollte der Name der Hintergrundaufgabenklasse sein, die dem Namespace vorangestellt ist.

Der Hintergrundaufgabentrigger steuert, wann die Hintergrundaufgabe ausgeführt wird. Eine Liste der möglichen Trigger finden Sie unter "SystemTrigger".

Mit diesem Code wird beispielsweise eine neue Hintergrundaufgabe erstellt und festgelegt, dass sie 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, um zu steuern, wann ihre Aufgabe ausgeführt wird, nachdem das Triggerereignis auftritt (optional). Wenn die Aufgabe beispielsweise erst ausgeführt werden soll, wenn der Benutzer vorhanden ist, verwenden Sie die Bedingung UserPresent. Eine Liste der möglichen Bedingungen finden Sie unter SystemConditionType.

Der folgende Beispielcode weist eine Bedingung zu, für die der Benutzer vorhanden sein muss:

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 , damit 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 RequestAccessAsync aufrufen, bevor Sie einen der Hintergrundtriggertypen registrieren.

Um sicherzustellen, dass Ihre universelle Windows-App nach der Veröffentlichung eines Updates weiterhin ordnungsgemäß ausgeführt wird, verwenden Sie den ServicingComplete -Trigger (siehe SystemTriggerType), um alle Konfigurationsänderungen nach dem Update auszuführen, z. B. das Migrieren der App-Datenbank und das Registrieren von Hintergrundaufgaben. Es empfiehlt sich, die Registrierung von Hintergrundaufgaben, die der vorherigen Version der App zugeordnet sind (siehe RemoveAccess), aufzuheben und Hintergrundaufgaben für die neue Version der App zu registrieren (siehe RequestAccessAsync).

Weitere Informationen finden Sie in den Richtlinien für Hintergrundaufgaben.

Behandeln des Abschlusses von Hintergrundaufgaben mithilfe von Ereignishandlern

Sie sollten eine Methode beim BackgroundTaskCompletedEventHandler registrieren, damit Ihre App Ergebnisse aus 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 ist, während sich Ihre App derzeit im Vordergrund befindet.)

  1. Schreiben Sie eine OnCompleted-Methode, um den Abschluss von Hintergrundaufgaben zu verarbeiten. Das Ergebnis der Hintergrundaufgabe kann z. B. zu einer Aktualisierung der Benutzeroberfläche führen. Der hier gezeigte Methodenbedarf ist für die OnCompleted-Ereignishandlermethode erforderlich, obwohl in diesem Beispiel nicht der Argumentparameter verwendet wird.

Der folgende Beispielcode erkennt den Abschluss der Hintergrundaufgabe und ruft eine Beispiel-UI-Aktualisierungsmethode auf, die eine Nachrichtenzeichenfolge verwendet.

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

Benutzeroberflächenaktualisierungen sollten asynchron ausgeführt werden, um zu vermeiden, dass der UI-Thread gehalten wird. Ein Beispiel finden Sie in der UpdateUI-Methode im Beispiel für Hintergrundaufgaben.

  1. Kehren Sie zurück zu der Stelle zurück, an der Sie die Hintergrundaufgabe registriert haben. Fügen Sie nach dieser Codezeile ein neues BackgroundTaskCompletedEventHandler-Objekt hinzu. Stellen Sie die OnCompleted-Methode als Parameter für den BackgroundTaskCompletedEventHandler-Konstruktor bereit.

Der folgende Beispielcode fügt dem BackgroundTaskRegistration einen BackgroundTaskCompletedEventHandler 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 jede Hintergrundaufgabe 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, indem Sie die Datei "Package.appxmanifest" öffnen.
  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 Der Hintergrundklasse ein, der für dieses Beispiel "Tasks.ExampleBackgroundTask" lautet.
  6. Schließen Sie den Manifest-Designer.

Das folgende Extensions-Element wird der 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 nun die Grundlagen zum Schreiben einer Hintergrundaufgabenklasse, zum Registrieren der Hintergrundaufgabe in Ihrer App und zum Erkennen der App bei Abschluss der Hintergrundaufgabe verstehen. Außerdem sollten Sie wissen, wie Sie das Anwendungsmanifest aktualisieren, damit Ihre App die Hintergrundaufgabe erfolgreich registrieren kann.

Hinweis

Laden Sie das Beispiel für Hintergrundaufgaben herunter, um ähnliche Codebeispiele im Kontext einer vollständigen und robusten UWP-App anzuzeigen, die Hintergrundaufgaben verwendet.

In den folgenden verwandten Themen finden Sie API-Referenz, konzeptionelle Anleitungen für Hintergrundaufgaben und ausführlichere Anweisungen zum Schreiben von Apps, die Hintergrundaufgaben verwenden.

Ausführliche Themen zu Anleitungen zu Hintergrundaufgaben

Leitfaden für Hintergrundaufgaben

Hintergrundaufgaben-API-Referenz