Creare e registrare un'attività in background out-of-process

API importanti

Creare una classe di attività in background e registrarla per l'esecuzione quando l'app non è in primo piano. Questo argomento illustra come creare e registrare un'attività in background eseguita in un processo separato rispetto al processo dell'app. Per eseguire operazioni in background direttamente nell'applicazione in primo piano, vedere Creare e registrare un'attività in background in-process.

Nota

Se usi un'attività in background per riprodurre elementi multimediali in background, vedere Riprodurre elementi multimediali in background per informazioni sui miglioramenti apportati a Windows 10, versione 1607, che rendono ciò molto più semplice.

Nota

Se si implementa un'attività in background out-of-process in un'applicazione desktop C# con .NET 6 o versione successiva, usare il supporto per la creazione di C#/WinRT per creare un componente Windows Runtime. Questo vale per le app che usano i SDK per app di Windows, WinUI 3, WPF o WinForms. Vedere l'esempio di attività In background.

Creare la classe di attività in background

È possibile eseguire il codice in background scrivendo classi che implementano l'interfaccia IBackgroundTask. Questo codice viene eseguito quando viene attivato un evento specifico usando, ad esempio, SystemTrigger o MaintenanceTrigger.

I passaggi seguenti illustrano come scrivere una nuova classe che implementa l'interfaccia IBackgroundTask.

  1. Creare un nuovo progetto per le attività in background e aggiungerlo alla soluzione. Per fare ciò, fai clic con il pulsante destro del mouse sul nodo della soluzione nel file Esplora soluzioni e selezionare Aggiungi>Nuovo progetto. Selezionare quindi il tipo di progetto Componente Windows Runtime, denominare il progetto e fare clic su OK.
  2. Fare riferimento al progetto di attività in background dal progetto di app piattaforma UWP (Universal Windows Platform). Per un'app C# o C++, nel progetto dell'app fare clic con il pulsante destro del mouse su Riferimenti e scegliere Aggiungi nuovo riferimento. In Soluzione selezionare Progetti e quindi selezionare il nome del progetto di attività in background e fare clic su OK.
  3. Nel progetto attività in background aggiungere una nuova classe che implementa l'interfaccia IBackgroundTask. Il metodo IBackgroundTask.Run è un punto di ingresso obbligatorio che verrà chiamato quando viene attivato l'evento specificato. Questo metodo è obbligatorio in ogni attività in background.

Nota

La classe di attività in background stessa e tutte le altre classi nel progetto di attività in background devono essere classi pubbliche che sono nascoste (o finali).

Il codice di esempio seguente mostra un punto di partenza molto semplice per una classe di attività in background.

// 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. Se esegui codice asincrono nell'attività in background, l'attività in background dovrà utilizzare un differimento. Se non si usa un differimento, il processo dell'attività in background può terminare in modo imprevisto se il metodo Run restituisce un risultato prima dell'esecuzione del lavoro asincrono fino al completamento.

Richiedere il differimento nel metodo Run prima di chiamare il metodo asincrono. Salvare il differimento a un membro dati della classe in modo che sia possibile accedervi dal metodo asincrono. Dichiarare completo il differimento dopo il completamento del codice asincrono.

Il codice di esempio seguente ottiene il differimento, lo salva e lo rilascia al termine del codice asincrono.

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

Nota

In C# i metodi asincroni dell'attività in background possono essere chiamati usando le parole chiave async/await. In C++/CX è possibile ottenere un risultato simile usando una catena di attività.

Per ulteriori informazioni sui modelli asincroni, vedere Programmazione asincrona. Per altri esempi di come usare i differimenti per impedire l'arresto anticipato di un'attività in background, vedere l'esempio di attività in background.

I passaggi seguenti vengono completati in una delle classi dell'app, ad esempio MainPage.xaml.cs.

Nota

È anche possibile creare una funzione dedicata alla registrazione delle attività in background. Vedere Registrare un'attività in background. In questo caso, invece di usare i tre passaggi successivi, è sufficiente costruire il trigger e fornirlo alla funzione di registrazione insieme al nome dell'attività, al punto di ingresso dell'attività e (facoltativamente) a una condizione.

Registrare l'attività in background da eseguire

  1. Verificare se l'attività in background è già registrata eseguendo l'iterazione tramite la proprietà BackgroundTaskRegistration.AllTasks. Questo passaggio è importante. Se l'app non verifica la presenza di registrazioni di attività in background esistenti, potrebbe registrare facilmente l'attività più volte, causando problemi con le prestazioni e il numero massimo di tempo di CPU disponibile dell'attività prima che il lavoro possa essere completato.

Nell'esempio seguente viene eseguita l'iterazione nella proprietà AllTasks e viene impostata una variabile flag su true se l'attività è già registrata.

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. Se l'attività in background non è già registrata, usare BackgroundTaskBuilder per creare un'istanza dell'attività in background. Il punto di ingresso dell'attività deve essere il nome della classe di attività in background preceduta dallo spazio dei nomi.

Il trigger dell'attività in background controlla quando verrà eseguita l'attività in background. Per un elenco dei possibili trigger, vedere SystemTrigger.

Ad esempio, questo codice crea una nuova attività in background e la imposta per l'esecuzione quando si verifica il trigger TimeZoneChanged:

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. È possibile aggiungere una condizione per controllare quando l'attività verrà eseguita dopo che si verifica l'evento trigger (opzionale). Ad esempio, se non vuoi che l'attività venga eseguita finché l'utente non è presente, utilizza la condizione UserPresent. Per un elenco delle possibili condizioni, vedere SystemConditionType.

Il codice di esempio seguente assegna una condizione che richiede che l'utente sia presente:

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. Registrare l'attività in background chiamando il metodo Register nell'oggetto BackgroundTaskBuilder. Archiviare il risultato BackgroundTaskRegistration in modo che possa essere usato nel passaggio successivo.

Il codice seguente registra l'attività in background e archivia il risultato:

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

Nota

Le app Universal Windows devono chiamare RequestAccessAsync prima di registrare uno dei tipi di trigger in background.

Per assicurarsi che l'app di Windows universale continui a funzionare correttamente dopo il rilascio di un aggiornamento, usare il trigger ServicingComplete (vedere SystemTriggerType) per eseguire eventuali modifiche di configurazione post-aggiornamento, ad esempio la migrazione del database dell'app e la registrazione delle attività in background. È consigliabile annullare la registrazione delle attività in background associate alla versione precedente dell'app (vedere RemoveAccess) e registrare le attività in background per la nuova versione dell'app (vedere RequestAccessAsync) in questo momento.

Per maggiori informazioni, vedere Linee guida per le attività in background.

Gestire il completamento delle attività in background usando i gestori eventi

Devi registrare un metodo con BackgroundTaskCompletedEventHandler, in modo che l'app possa ottenere risultati dall'attività in background. Quando l'app viene avviata o ripresa, il metodo contrassegnato verrà chiamato se l'attività in background è stata completata dall'ultima volta che l'app era in primo piano. Il metodo OnCompleted verrà chiamato immediatamente se l'attività in background viene completata mentre l'app è attualmente in primo piano.

  1. Scrivere un metodo OnCompleted per gestire il completamento delle attività in background. Ad esempio, il risultato dell'attività in background potrebbe causare un aggiornamento dell'interfaccia utente. Il footprint del metodo illustrato di seguito è obbligatorio per il metodo del gestore eventi OnCompleted, anche se questo esempio non usa il parametro args.

Il codice di esempio seguente riconosce il completamento dell'attività in background e chiama un metodo di aggiornamento dell'interfaccia utente di esempio che accetta una stringa di messaggio.

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

Nota

Gli aggiornamenti dell'interfaccia utente devono essere eseguiti in modo asincrono, per evitare di tenere premuto il thread dell'interfaccia utente. Per un esempio, vedere il metodo UpdateUI nell'esempio di attività in background.

  1. Tornare alla posizione in cui è stata registrata l'attività in background. Dopo tale riga di codice, aggiungere un nuovo oggetto BackgroundTaskCompletedEventHandler. Specificare il metodo OnCompleted come parametro per il costruttore BackgroundTaskCompletedEventHandler.

Il codice di esempio seguente aggiunge BackgroundTaskCompletedEventHandler a BackgroundTaskRegistration:

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

Dichiarare nel manifesto dell'app che l'app usa attività in background

Prima che l'app possa eseguire attività in background, devi dichiarare ogni attività in background nel manifesto dell'app. Se l'app tenta di registrare un'attività in background con un trigger non elencato nel manifesto, la registrazione dell'attività in background avrà esito negativo con un errore "classe di runtime non registrata".

  1. Aprire la finestra di progettazione del manifesto del pacchetto aprendo il file denominato Package.appxmanifest.
  2. Aprire la scheda Dichiarazioni.
  3. Dall'elenco a discesa Dichiarazioni disponibili selezionare Attività di background e fare clic su Aggiungi.
  4. Selezionare la casella di controllo Evento di sistema.
  5. Nella casella di testo Punto di ingresso immettere lo spazio dei nomi e il nome della classe in background, che per questo esempio è Tasks.ExampleBackgroundTask.
  6. Chiudere Progettazione manifesto.

L'elemento Extensions seguente viene aggiunto al file Package.appxmanifest per registrare l'attività in background:

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

Riepilogo e passaggi successivi

È ora necessario comprendere le nozioni di base su come scrivere una classe di attività in background, come registrare l'attività in background dall'interno dell'app e come riconoscere l'app al termine dell'attività in background. È anche necessario comprendere come aggiornare il manifesto dell'applicazione in modo che l'app possa registrare correttamente l'attività in background.

Nota

Scarica l'esempio di attività in background per visualizzare esempi di codice simili nel contesto di un'app UWP completa e affidabile che usa attività in background.

Vedere gli argomenti correlati seguenti per informazioni di riferimento sulle API, indicazioni concettuali sulle attività in background e istruzioni più dettagliate per la scrittura di app che usano attività in background.

Argomenti dettagliati relativi alle istruzioni per le attività in background

Linee guida per attività in background

Informazioni di riferimento sulle API delle attività in background