Delen via


Een niet-procesachtergrondtaak maken en registreren

Belangrijke API's

Maak een achtergrondtaakklasse en registreer deze om uit te voeren wanneer uw app zich niet op de voorgrond bevindt. In dit onderwerp ziet u hoe u een achtergrondtaak maakt en registreert die in een afzonderlijk proces wordt uitgevoerd dan het proces van uw app. Zie Een achtergrondtaak maken en registrerenom achtergrondtaken rechtstreeks in de voorgrondtoepassing uit te voeren.

Opmerking

Als u een achtergrondtaak gebruikt om media op de achtergrond af te spelen, raadpleegt u Media afspelen op de achtergrond voor informatie over verbeteringen in Windows 10, versie 1607, waardoor het veel eenvoudiger wordt.

Opmerking

Als u een niet-procesachtergrondtaak implementeert in een C#-bureaubladtoepassing met .NET 6 of hoger, gebruikt u de C#/WinRT-creatieondersteuning om een Windows Runtime-onderdeel te maken. Dit geldt voor apps die gebruikmaken van de Windows App SDK, WinUI 3, WPF of WinForms. Zie het achtergrondtaakvoorbeeld voor een voorbeeld.

Maak de klasse Achtergrondtaak

U kunt code op de achtergrond uitvoeren door klassen te schrijven die de interface IBackgroundTask implementeren. Deze code wordt uitgevoerd wanneer een specifieke gebeurtenis wordt geactiveerd met bijvoorbeeld SystemTrigger of MaintenanceTrigger.

De volgende stappen laten zien hoe u een nieuwe klasse schrijft waarmee de interface IBackgroundTask wordt geïmplementeerd.

  1. Maak een nieuw project voor achtergrondtaken en voeg dit toe aan uw oplossing. Klik hiervoor met de rechtermuisknop op het oplossingsknooppunt in de Solution Explorer- en selecteer Add>New Project. Selecteer vervolgens het Windows Runtime-onderdeel projecttype, geef het project een naam en klik op OK.
  2. Verwijs naar het achtergrondtakenproject vanuit uw UWP-app-project (Universal Windows Platform). Voor een C#- of C++-app klikt u in uw app-project met de rechtermuisknop op Verwijzingen en selecteert u Nieuwe verwijzing toevoegen. Selecteer onder SolutionProjects en selecteer vervolgens de naam van uw achtergrondtaakproject en klik op OK.
  3. Voeg aan het achtergrondtakenproject een nieuwe klasse toe waarmee de interface IBackgroundTask wordt geïmplementeerd. De methode IBackgroundTask.Run is een vereist toegangspunt dat wordt aangeroepen wanneer de opgegeven gebeurtenis wordt geactiveerd; deze methode is vereist voor elke achtergrondtaak.

Opmerking

De achtergrondtaakklasse zelf, en alle andere klassen in het achtergrondtaakproject, moeten worden openbare klassen die zijn verzegelde (of definitieve).

In de volgende voorbeeldcode ziet u een zeer eenvoudig uitgangspunt voor een achtergrondtaakklasse.

// 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. Als u asynchrone code uitvoert in uw achtergrondtaak, moet uw achtergrondtaak een uitstel gebruiken. Als u geen uitstel gebruikt, kan het achtergrondtaakproces onverwacht worden beëindigd als de methode Uitvoeren retourneert voordat asynchroon werk tot voltooiing is uitgevoerd.

Vraag het uitstel aan in de methode Run voordat u de asynchrone methode aanroept. Sla het uitstel op in een klassegegevenslid, zodat deze toegankelijk is via de asynchrone methode. Declareer het uitstel voltooid nadat de asynchrone code is voltooid.

Met de volgende voorbeeldcode wordt de uitstel opgevraagd, opgeslagen en vrijgegeven wanneer de asynchrone code is voltooid.

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

Opmerking

In C# kunnen de asynchrone methoden van uw achtergrondtaak worden aangeroepen met behulp van de asynchrone/wachtende trefwoorden. In C++/CX kan een vergelijkbaar resultaat worden bereikt met behulp van een taakketen.

Zie Asynchrone programmeringvoor meer informatie over asynchrone patronen. Zie het voorbeeld van achtergrondtaakvoor meer voorbeelden van het gebruik van uitsteltaken om te voorkomen dat een achtergrondtaak vroeg stopt.

De volgende stappen worden uitgevoerd in een van uw app-klassen (bijvoorbeeld MainPage.xaml.cs).

Opmerking

U kunt ook een functie maken die is toegewezen aan het registreren van achtergrondtaken. Zie Een achtergrondtaak registreren. In dat geval kunt u in plaats van de volgende drie stappen de trigger maken en deze aan de registratiefunctie opgeven, samen met de taaknaam, het beginpunt van de taak en (optioneel) een voorwaarde.

De achtergrondtaak registreren die moet worden uitgevoerd

  1. Ontdek of de achtergrondtaak al is geregistreerd door door de eigenschap BackgroundTaskRegistration.AllTasks te itereren. Deze stap is belangrijk; als uw app niet controleert op bestaande registraties van achtergrondtaken, kan de taak eenvoudig meerdere keren worden geregistreerd, waardoor problemen met de prestaties worden veroorzaakt en de beschikbare CPU-tijd van de taak wordt beperkt voordat het werk kan worden voltooid.

In het volgende voorbeeld wordt de eigenschap AllTasks doorlopen en wordt een vlagvariabele ingesteld op true als de taak al is geregistreerd.

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. Als de achtergrondtaak nog niet is geregistreerd, gebruikt u BackgroundTaskBuilder om een exemplaar van uw achtergrondtaak te maken. Het taakinvoerpunt moet de naam zijn van de achtergrondtaakklasse die wordt voorafgegaan door de naamruimte.

De trigger van de achtergrondtaak bepaalt wanneer de achtergrondtaak wordt uitgevoerd. Zie SystemTriggervoor een lijst met mogelijke triggers.

Met deze code maakt u bijvoorbeeld een nieuwe achtergrondtaak en stelt u deze in om uit te voeren wanneer de trigger TimeZoneChanged plaatsvindt:

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. U kunt een voorwaarde toevoegen om te bepalen wanneer uw taak wordt uitgevoerd nadat de trigger-gebeurtenis plaatsvindt (optioneel). Als u bijvoorbeeld niet wilt dat de taak wordt uitgevoerd totdat de gebruiker aanwezig is, gebruikt u de voorwaarde UserPresent. Zie SystemConditionTypevoor een lijst met mogelijke voorwaarden.

Met de volgende voorbeeldcode wordt een voorwaarde toegewezen die vereist dat de gebruiker aanwezig is:

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. Registreer de achtergrondtaak door de methode Register aan te roepen op het BackgroundTaskBuilder-object. Sla de BackgroundTaskRegistration resultaat op, zodat deze in de volgende stap kan worden gebruikt.

Met de volgende code wordt de achtergrondtaak geregistreerd en wordt het resultaat opgeslagen:

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

Opmerking

Universele Windows-apps moeten RequestAccessAsync- aanroepen voordat een van de typen achtergrondtriggers wordt geregistreerd.

Gebruik de ServicingComplete- (zie SystemTriggerType) om ervoor te zorgen dat uw Universal Windows-app correct wordt uitgevoerd nadat u een update hebt uitgebracht, om configuratiewijzigingen na de update uit te voeren, zoals het migreren van de database van de app en het registreren van achtergrondtaken. Het is raadzaam om de registratie van achtergrondtaken die zijn gekoppeld aan de vorige versie van de app ongedaan te maken (zie RemoveAccess) en achtergrondtaken te registreren voor de nieuwe versie van de app (zie RequestAccessAsync) op dit moment.

Zie Richtlijnen voor achtergrondtakenvoor meer informatie.

Afhandelen van de voltooiing van achtergrondtaken met event handlers

U moet een methode registreren bij de BackgroundTaskCompletedEventHandler, zodat uw app resultaten van de achtergrondtaak kan ophalen. Wanneer de app wordt gestart of hervat, wordt de gemarkeerde methode aangeroepen als de achtergrondtaak is voltooid sinds de laatste keer dat de app zich op de voorgrond bevond. (De methode OnCompleted wordt onmiddellijk aangeroepen als de achtergrondtaak is voltooid terwijl uw app zich momenteel op de voorgrond bevindt.)

  1. Schrijf een OnCompleted-methode om de voltooiing van achtergrondtaken af te handelen. Het resultaat van de achtergrondtaak kan bijvoorbeeld een UI-update veroorzaken. De hier weergegeven methodevoetafdruk is vereist voor de gebeurtenis-handlermethode OnCompleted, ook al gebruikt dit voorbeeld niet de args parameter.

De volgende voorbeeldcode herkent voltooiing van achtergrondtaken en roept een voorbeeld-UI-updatemethode aan die een berichttekenreeks gebruikt.

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

Opmerking

UI-updates moeten asynchroon worden uitgevoerd om te voorkomen dat de UI-thread wordt opgehouden. Zie bijvoorbeeld de UpdateUI-methode in het voorbeeld van achtergrondtaak.

  1. Ga terug naar de locatie waar u de achtergrondtaak hebt geregistreerd. Voeg na die coderegel een nieuw BackgroundTaskCompletedEventHandler-object toe. Geef de OnCompleted-methode op als de parameter voor de BackgroundTaskCompletedEventHandler constructor.

Met de volgende voorbeeldcode wordt een BackgroundTaskCompletedEventHandler- toegevoegd aan de BackgroundTaskRegistration-:

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

Declareren in het app-manifest dat uw app achtergrondtaken gebruikt

Voordat uw app achtergrondtaken kan uitvoeren, moet u elke achtergrondtaak in het app-manifest declareren. Als uw app probeert een achtergrondtaak te registreren met een trigger die niet wordt vermeld in het manifest, mislukt de registratie van de achtergrondtaak met de fout 'Runtime-klasse niet geregistreerd'.

  1. Open de ontwerpfunctie voor pakketmanifest door het bestand Package.appxmanifest te openen.
  2. Open het tabblad Declaraties.
  3. Selecteer uit de vervolgkeuzelijst Beschikbare declaraties de optie Achtergrondtaken, en klik op Toevoegen.
  4. Schakel het selectievakje Systeem gebeurtenis in.
  5. Voer in het invoerpunt: tekstvak de naamruimte en de naam van uw achtergrondklasse in. Dit voorbeeld is Tasks.ExampleBackgroundTask.
  6. Sluit de manifestontwerper.

Het volgende uitbreidingselement wordt toegevoegd aan het bestand Package.appxmanifest om de achtergrondtaak te registreren:

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

Samenvatting en volgende stappen

U moet nu de basisbeginselen begrijpen van het schrijven van een achtergrondtaakklasse, het registreren van de achtergrondtaak vanuit uw app en het herkennen van uw app wanneer de achtergrondtaak is voltooid. U moet ook begrijpen hoe u het toepassingsmanifest bijwerkt, zodat uw app de achtergrondtaak kan registreren.

Opmerking

Download het voorbeeld van achtergrondtaken om vergelijkbare codevoorbeelden te zien in de context van een volledige en robuuste UWP-app die achtergrondtaken gebruikt.

Zie de volgende verwante onderwerpen voor API-naslaginformatie, conceptuele richtlijnen voor achtergrondtaken en gedetailleerdere instructies voor het schrijven van apps die achtergrondtaken gebruiken.

Gedetailleerde onderwerpen voor instructie over achtergrondtaken

Richtlijnen voor Achtergrondtaken

API-referentie voor achtergrondtaken