Partilhar via


Criar e registrar uma tarefa em segundo plano fora do processo.

APIs importantes

Crie uma classe de tarefa em segundo plano e registre-a para ser executada quando seu aplicativo não estiver em primeiro plano. Este tópico demonstra como criar e registrar uma tarefa em segundo plano que é executada em um processo separado do processo do aplicativo. Para fazer o trabalho em segundo plano diretamente no aplicativo em primeiro plano, consulte Criar e registrar uma tarefa em segundo plano em processo.

Observação

Se você usar uma tarefa em segundo plano para reproduzir mídia em segundo plano, consulte Reproduzir mídia em segundo plano para obter informações sobre melhorias no Windows 10, versão 1607, que facilitam muito.

Observação

Se você estiver implementando uma tarefa em segundo plano fora do processo em um aplicativo da área de trabalho C# com o .NET 6 ou posterior, use o suporte à criação de C#/WinRT para criar um Componente do Tempo de Execução do Windows. Isso se aplica a aplicativos que usam o SDK do Aplicativo Windows, WinUI 3, WPF ou WinForms. Consulte o exemplo de tarefa em segundo plano para obter um exemplo.

Criar a classe Background Task

Você pode executar código em segundo plano escrevendo classes que implementam a interface IBackgroundTask . Esse código é executado quando um evento específico é disparado usando, por exemplo, SystemTrigger ou MaintenanceTrigger.

As etapas a seguir mostram como escrever uma nova classe que implementa a interface IBackgroundTask .

  1. Crie um novo projeto para tarefas em segundo plano e adicione-o à sua solução. Para fazer isso, clique com o botão direito do mouse no nó da solução no Gerenciador de Soluções e selecione Adicionar>Novo Projeto. Em seguida, selecione o tipo de projeto Componente do Tempo de Execução do Windows, nomeie o projeto e clique em OK.
  2. Faça referência ao projeto de tarefas em segundo plano do seu projeto de aplicativo UWP (Plataforma Universal do Windows). Para um aplicativo C# ou C++, em seu projeto de aplicativo, clique com o botão direito do mouse em Referências e selecione Adicionar Nova Referência. Em Solução, selecione Projetos e, em seguida, selecione o nome do seu projeto de tarefa em segundo plano e clique em Ok.
  3. Para o projeto de tarefas em segundo plano, adicione uma nova classe que implemente a interface IBackgroundTask . O método IBackgroundTask.Run é um ponto de entrada necessário que será chamado quando o evento especificado for disparado; esse método é necessário em todas as tarefas em segundo plano.

Observação

A própria classe de tarefa em segundo plano — e todas as outras classes no projeto de tarefa em segundo plano — precisam ser classes públicas seladas (ou finais).

O código de exemplo a seguir mostra um ponto de partida muito básico para uma classe de tarefa em segundo plano.

// 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 você executar qualquer código assíncrono em sua tarefa em segundo plano, sua tarefa em segundo plano precisará usar um adiamento. Se você não usar um adiamento, o processo de tarefa em segundo plano poderá ser encerrado inesperadamente se o método Run retornar antes que qualquer trabalho assíncrono tenha sido executado até a conclusão.

Solicite o adiamento no método Run antes de chamar o método assíncrono. Salve o adiamento em um membro de dados de classe para que ele possa ser acessado a partir do método assíncrono. Declare o adiamento concluído após a conclusão do código assíncrono.

O código de exemplo a seguir obtém o adiamento, salva-o e libera-o quando o código assíncrono é concluído.

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

Observação

Em C#, os métodos assíncronos da tarefa em segundo plano podem ser chamados usando as palavras-chave async/await . Em C++/CX, um resultado semelhante pode ser obtido usando uma cadeia de tarefas.

Para obter mais informações sobre padrões assíncronos, consulte Programação assíncrona. Para obter exemplos adicionais de como usar adiamentos para impedir que uma tarefa em segundo plano pare antecipadamente, consulte o exemplo de tarefa em segundo plano.

As etapas a seguir são concluídas em uma de suas classes de aplicativo (por exemplo, MainPage.xaml.cs).

Observação

Você também pode criar uma função dedicada ao registro de tarefas em segundo plano — consulte Registrar uma tarefa em segundo plano. Nesse caso, em vez de usar as próximas três etapas, você pode simplesmente construir o gatilho e fornecê-lo à função de registro junto com o nome da tarefa, o ponto de entrada da tarefa e (opcionalmente) uma condição.

Registrar a tarefa em segundo plano a ser executada

  1. Descubra se a tarefa em segundo plano já está registrada iterando por meio da propriedade BackgroundTaskRegistration.AllTasks. Esta etapa é importante; se o aplicativo não verificar se há registros de tarefas em segundo plano existentes, ele poderá registrar facilmente a tarefa várias vezes, causando problemas de desempenho e maximizando o tempo de CPU disponível da tarefa antes que o trabalho possa ser concluído.

O exemplo a seguir itera na propriedade AllTasks e define uma variável de sinalizador como true se a tarefa já estiver registrada.

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 a tarefa em segundo plano ainda não estiver registrada, use BackgroundTaskBuilder para criar uma instância de sua tarefa em segundo plano. O ponto de entrada da tarefa deve ser o nome da classe de tarefa em segundo plano prefixada pelo namespace.

O gatilho de tarefa em segundo plano controla quando a tarefa em segundo plano será executada. Para obter uma lista de possíveis gatilhos, consulte SystemTrigger.

Por exemplo, esse código cria uma nova tarefa em segundo plano e a define para ser executada quando ocorre o gatilho 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. Você pode adicionar uma condição para controlar quando sua tarefa será executada após a ocorrência do evento de gatilho (opcional). Por exemplo, se você não quiser que a tarefa seja executada até que o usuário esteja presente, use a condição UserPresent. Para obter uma lista de condições possíveis, consulte SystemConditionType.

O código de exemplo a seguir atribui uma condição que exige que o usuário esteja 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. Registre a tarefa em segundo plano chamando o método Register no objeto BackgroundTaskBuilder . Armazene o resultado BackgroundTaskRegistration para que ele possa ser usado na próxima etapa.

O código a seguir registra a tarefa em segundo plano e armazena o resultado:

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

Observação

Os aplicativos universais do Windows devem chamar RequestAccessAsync antes de registrar qualquer um dos tipos de gatilho em segundo plano.

Para garantir que seu aplicativo Universal do Windows continue a ser executado corretamente após o lançamento de uma atualização, use o gatilho ServicingComplete (consulte SystemTriggerType) para executar quaisquer alterações de configuração pós-atualização, como migrar o banco de dados do aplicativo e registrar tarefas em segundo plano. É uma prática recomendada cancelar o registro de tarefas em segundo plano associadas à versão anterior do aplicativo (consulte RemoveAccess) e registrar tarefas em segundo plano para a nova versão do aplicativo (consulte RequestAccessAsync) no momento.

Para obter mais informações, consulte Diretrizes para tarefas em segundo plano.

Manipular a conclusão de tarefas em segundo plano usando manipuladores de eventos

Você deve registrar um método com o BackgroundTaskCompletedEventHandler, para que seu aplicativo possa obter resultados da tarefa em segundo plano. Quando o aplicativo for iniciado ou retomado, o método marcado será chamado se a tarefa em segundo plano tiver sido concluída desde a última vez que o aplicativo esteve em primeiro plano. (O método OnCompleted será chamado imediatamente se a tarefa em segundo plano for concluída enquanto o aplicativo estiver em primeiro plano.)

  1. Escreva um método OnCompleted para lidar com a conclusão de tarefas em segundo plano. Por exemplo, o resultado da tarefa em segundo plano pode causar uma atualização da interface do usuário. O volume do método mostrado aqui é necessário para o método do manipulador de eventos OnCompleted, mesmo que este exemplo não use o parâmetro args .

O código de exemplo a seguir reconhece a conclusão da tarefa em segundo plano e chama um método de atualização de interface do usuário de exemplo que usa uma cadeia de caracteres de mensagem.

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

Observação

As atualizações da interface do usuário devem ser executadas de forma assíncrona, para evitar a retenção do thread da interface do usuário. Para obter um exemplo, consulte o método UpdateUI no exemplo de tarefa em segundo plano.

  1. Volte para onde você registrou a tarefa em segundo plano. Após essa linha de código, adicione um novo objeto BackgroundTaskCompletedEventHandler. Forneça seu método OnCompleted como o parâmetro para o construtor BackgroundTaskCompletedEventHandler .

O código de exemplo a seguir adiciona um BackgroundTaskCompletedEventHandler ao BackgroundTaskRegistration:

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

Declare no manifesto do aplicativo que seu aplicativo usa tarefas em segundo plano

Antes que seu aplicativo possa executar tarefas em segundo plano, você deve declarar cada tarefa em segundo plano no manifesto do aplicativo. Se o aplicativo tentar registrar uma tarefa em segundo plano com um gatilho que não está listado no manifesto, o registro da tarefa em segundo plano falhará com um erro "classe de runtime não registrada".

  1. Abra o designer de manifesto do pacote abrindo o arquivo chamado Package.appxmanifest.
  2. Abra a guia Declarações .
  3. No menu suspenso Declarações disponíveis, selecione Tarefas em segundo plano e clique em Adicionar.
  4. Marque a caixa de seleção Evento do sistema.
  5. Na caixa de texto Ponto de entrada:, insira o namespace e o nome da classe em segundo plano que, para este exemplo, é Tasks.ExampleBackgroundTask.
  6. Feche o designer de manifesto.

O seguinte elemento Extensions é adicionado ao arquivo Package.appxmanifest para registrar a tarefa em segundo plano:

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

Resumo e próximas etapas

Agora você deve entender as noções básicas de como escrever uma classe de tarefa em segundo plano, como registrar a tarefa em segundo plano de dentro do seu aplicativo e como fazer com que seu aplicativo reconheça quando a tarefa em segundo plano for concluída. Você também deve entender como atualizar o manifesto do aplicativo para que seu aplicativo possa registrar com êxito a tarefa em segundo plano.

Observação

Baixe o exemplo de tarefa em segundo plano para ver exemplos de código semelhantes no contexto de um aplicativo UWP completo e robusto que usa tarefas em segundo plano.

Consulte os tópicos relacionados a seguir para obter referência de API, diretrizes conceituais de tarefas em segundo plano e instruções mais detalhadas para escrever aplicativos que usam tarefas em segundo plano.

Tópicos instrucionais detalhados da tarefa em segundo plano

Diretrizes de tarefas em segundo plano

Referência da API de tarefa em segundo plano