Sdílet prostřednictvím


Vytvoření a registrace úlohy na pozadí mimo proces

důležitá rozhraní API

Vytvořte třídu úloh na pozadí a zaregistrujte ji, aby se spustila, když vaše aplikace není v popředí. Toto téma ukazuje, jak vytvořit a zaregistrovat úlohu na pozadí, která běží v samostatném procesu, než je proces vaší aplikace. Pokud chcete vykonávat práci na pozadí přímo v popřední aplikaci, přečtěte si Vytvoření a registrace úlohy na pozadí v rámci procesu.

Poznámka:

Pokud k přehrávání médií na pozadí používáte úlohu na pozadí, viz Přehrávání médií na pozadí pro informace o vylepšeních ve Windows 10, verzi 1607, které tuto činnost výrazně usnadňují.

Poznámka:

Pokud implementujete úlohu na pozadí mimo proces v desktopové aplikaci C# s .NET 6 nebo novějším, použijte podporu vytváření obsahu C#/WinRT k vytvoření komponenty prostředí Windows Runtime. To platí pro aplikace používající sadu Windows App SDK, WinUI 3, WPF nebo WinForms. Najděte příklad v ukázce úlohy na pozadí .

Vytvořte třídu úlohy na pozadí

Kód můžete spustit na pozadí psaním tříd, které implementují IBackgroundTask rozhraní. Tento kód se spustí, když je konkrétní událost aktivována, například pomocí SystemTrigger nebo MaintenanceTrigger.

Následující kroky ukazují, jak napsat novou třídu, která implementuje IBackgroundTask rozhraní.

  1. Vytvořte nový projekt pro úkoly na pozadí a přidejte ho do svého řešení. Uděláte to tak, že v Průzkumníku řešení kliknete pravým tlačítkem na uzel řešení a vyberete Přidat>nový projekt. Pak vyberte typ projektu komponent prostředí Windows Runtime , pojmenujte projekt a klikněte na tlačítko OK.
  2. Odkazujte na projekt úkolů na pozadí z vašeho projektu aplikace pro Univerzální platformu Windows (UWP). V případě aplikace C# nebo C++ klikněte v projektu aplikace pravým tlačítkem myši na Odkazy a vyberte Přidat nový odkaz. V části Řešenízvolte Projekty a pak zvolte název projektu pro úlohu na pozadí a klikněte na ok.
  3. Do projektu úkolů na pozadí přidejte novou třídu, která implementuje rozhraní IBackgroundTask . IBackgroundTask.Run metoda je povinný vstupní bod, který bude volán při aktivaci zadané události; tato metoda je vyžadována v každé úloze na pozadí.

Poznámka:

Samotná třída úkolu na pozadí a všechny ostatní třídy v projektu úkolů na pozadí musí být veřejné třídy, které jsou zapečetěné (nebo konečné).

Následující ukázkový kód ukazuje velmi základní výchozí bod třídy úlohy na pozadí.

// 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. Pokud v úloze na pozadí spustíte nějaký asynchronní kód, musí úloha na pozadí použít odložení. Pokud nepoužíváte odložení, proces úlohy na pozadí se může neočekávaně ukončit, pokud metoda Run vrátí hodnotu před dokončením jakýchkoli asynchronních operací.

Před voláním asynchronní metody požádejte o odložení metody Run . Uložte odložení do datového členu třídy, aby k němu bylo možné přistupovat z asynchronní metody. Po dokončení asynchronního kódu deklarujte dokončení odložení.

Následující ukázkový kód získá odložení, uloží ho a uvolní ho po dokončení asynchronního kódu.

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

Poznámka:

V jazyce C# je možné volat asynchronní metody úlohy na pozadí pomocí klíčových slov async/await. V jazyce C++/CX lze podobný výsledek dosáhnout pomocí řetězu úkolů.

Další informace o asynchronních vzorech naleznete v tématu Asynchronní programování. Další příklady, jak použít odložení, aby se zabránilo předčasnému ukončení úlohy na pozadí, najdete v ukázce úlohy na pozadí .

Následující kroky jsou dokončeny v některé z vašich tříd aplikací (například MainPage.xaml.cs).

Poznámka:

Můžete také vytvořit funkci vyhrazenou pro registraci úloh na pozadí – viz Registrace úlohy na pozadí. V takovém případě můžete místo použití dalších tří kroků jednoduše vytvořit trigger a zadat ji funkci registrace spolu s názvem úlohy, vstupním bodem úkolu a (volitelně) podmínkou.

Zaregistrujte úlohu na pozadí pro spuštění

  1. Zjistěte, zda je úloha na pozadí již zaregistrována iterací prostřednictvím BackgroundTaskRegistration.AllTasks vlastnost. Tento krok je důležitý; Pokud vaše aplikace nekontroluje existující registrace úloh na pozadí, může úlohu snadno zaregistrovat vícekrát, což může způsobit problémy s výkonem a maximálním limitem dostupného času procesoru úlohy, než bude možné dokončit práci.

Následující příklad iteruje přes vlastnost AllTasks a nastaví příznakovou proměnnou na true, pokud je úkol již zaregistrován.

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. Pokud úloha na pozadí ještě není zaregistrovaná, vytvořte instanci úlohy na pozadí pomocí nástroje BackgroundTaskBuilder . Vstupním bodem úkolu by měl být název třídy vaší úlohy na pozadí, prefiksovaný názvem oboru.

Spouštěč úlohy na pozadí určuje, kdy se úloha na pozadí spustí. Seznam možných triggerů najdete v tématu SystemTrigger.

Tento kód například vytvoří novou úlohu na pozadí a nastaví ji tak, aby se spustila, když dojde k triggeru 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. Můžete přidat podmínku pro řízení, kdy se úloha spustí po události triggeru (volitelné). Pokud například nechcete, aby úloha běžela, dokud uživatel není k dispozici, použijte podmínku UserPresent. Seznam možných podmínek naleznete v části SystemConditionType.

Následující ukázkový kód přiřadí podmínku, která vyžaduje, aby uživatel byl přítomný:

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. Zaregistrujte úlohu na pozadí voláním Metody Register na BackgroundTaskBuilder objektu. Uložte výsledek BackgroundTaskRegistration , abyste ho mohli použít v dalším kroku.

Následující kód zaregistruje úlohu na pozadí a uloží výsledek:

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

Poznámka:

Univerzální aplikace pro Windows musí před registrací některého z typů triggerů na pozadí volat RequestAccessAsync.

Pokud chcete zajistit, aby vaše univerzální aplikace pro Windows po vydání aktualizace fungovala správně, použijte trigger ServicingComplete (viz SystemTriggerType) k provedení jakýchkoli změn konfigurace po aktualizaci, jako je migrace databáze aplikace a registrace úloh na pozadí. Osvědčeným postupem je zrušit registraci úloh na pozadí přidružených k předchozí verzi aplikace (viz RemoveAccess) a zaregistrovat úlohy na pozadí pro novou verzi aplikace (viz RequestAccessAsync).

Další informace naleznete v pokynech pro úlohy na pozadí (viz ).

Zpracujte dokončování úkolů na pozadí pomocí obslužných rutin událostí

Metodu byste měli zaregistrovat s BackgroundTaskCompletedEventHandler, aby vaše aplikace získala výsledky z úlohy na pozadí. Když je aplikace spuštěna nebo obnovena, označená metoda bude zavolána, pokud se úloha na pozadí dokončila od naposledy, kdy byla aplikace v popředí. (Metoda OnCompleted se zavolá okamžitě, pokud se úloha na pozadí dokončí, když je vaše aplikace aktuálně v popředí.)

  1. Napište metodu OnCompleted pro zpracování dokončení úloh na pozadí. Například výsledek úlohy na pozadí může způsobit aktualizaci uživatelského rozhraní. Pro metodu obslužné rutiny události OnCompleted je vyžadována stopa metody, i když tento příklad nepoužívá parametr args.

Následující ukázkový kód rozpozná dokončení úlohy na pozadí a zavolá ukázkovou metodu aktualizace uživatelského rozhraní, která přebírá řetězec zprávy.

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

Poznámka:

Aktualizace uživatelského rozhraní by se měly provádět asynchronně, aby se zabránilo zablokování vlákna uživatelského rozhraní. Příklad najdete v metodě UpdateUI v ukázce úlohy na pozadí .

  1. Vraťte se zpět na místo, kde jste zaregistrovali úlohu na pozadí. Za tento řádek kódu přidejte nový BackgroundTaskCompletedEventHandler objekt. Zadejte metodu OnCompleted jako parametr pro konstruktor BackgroundTaskCompletedEventHandler .

Následující ukázkový kód přidá BackgroundTaskCompletedEventHandler k BackgroundTaskRegistration:

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

Deklarujte v manifestu aplikace, že vaše aplikace používá úlohy na pozadí

Než bude aplikace moct spouštět úlohy na pozadí, musíte deklarovat každou úlohu na pozadí v manifestu aplikace. Pokud se vaše aplikace pokusí zaregistrovat úlohu na pozadí s triggerem, který není uvedený v manifestu, registrace úlohy na pozadí selže s chybou "Třída modulu runtime není zaregistrovaná".

  1. Otevřete návrhář manifestu balíčku otevřením souboru s názvem Package.appxmanifest.
  2. Otevřete kartu Deklarace.
  3. V rozevíracím seznamu Dostupné deklarace vyberte Úkoly na pozadí a klikněte na Přidat.
  4. Zaškrtněte políčko událostí systému .
  5. V textovém poli Vstupní bod: zadejte obor názvů a název vaší třídy pro pozadí, přičemž v tomto příkladu je to Tasks.ExampleBackgroundTask.
  6. Zavřete návrháře manifestu.

Do souboru Package.appxmanifest se přidá následující element Extensions, který zaregistruje úlohu na pozadí:

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

Shrnutí a další kroky

Teď byste měli rozumět základům psaní třídy úloh na pozadí, způsobu registrace úlohy na pozadí z aplikace a způsobu rozpoznávání aplikace při dokončení úlohy na pozadí. Měli byste také pochopit, jak aktualizovat manifest aplikace, aby vaše aplikace úspěšně zaregistrovala úlohu na pozadí.

Poznámka:

Stáhněte si ukázku úlohy na pozadí , abyste viděli podobné příklady kódu v kontextu kompletní a robustní aplikace UPW, která používá úlohy na pozadí.

V následujících souvisejících tématech najdete referenční informace k rozhraní API, koncepční pokyny k úlohám na pozadí a podrobnější pokyny pro psaní aplikací, které používají úlohy na pozadí.

Podrobná instruktážní témata pro úlohy na pozadí

Pokyny k úlohám na pozadí

Referenční rozhraní API pro úlohy na pozadí