Behandeln einer abgebrochenen HintergrundaufgabeHandle a cancelled background task

Wichtige APIsImportant APIs

Hier erfahren Sie, wie Sie eine Hintergrundaufgabe erstellen, die mithilfe des beständigen Speichers Abbruchanforderungen erkennt, die Ausführung beendet und den Abbruch an die App meldet.Learn how to make a background task that recognizes a cancellation request, stops work, and reports the cancellation to the app using persistent storage.

In diesem Thema wird davon ausgegangen, dass Sie bereits eine Hintergrundaufgaben Klasse erstellt haben, einschließlich der Run -Methode, die als Einstiegspunkt für den Hintergrund Task verwendet wird.This topic assumes you have already created a background task class, including the Run method that is used as the background task entry point. Um schnell mit dem Erstellen einer Hintergrundaufgabe zu beginnen, lesen Sie Erstellen und Registrieren einer Hintergrundaufgabe außerhalb von Prozessen oder Erstellen und Registrieren einer Hintergrundaufgabe innerhalb von Prozessen.To get started quickly building a background task, see Create and register an out-of-process background task or Create and register an in-process background task. Ausführlichere Informationen zu Bedingungen und Triggern finden Sie unter Unterstützen der App mit Hintergrundaufgaben.For more in-depth information on conditions and triggers, see Support your app with background tasks.

Dieses Thema gilt auch für Hintergrundaufgaben innerhalb von Prozessen.This topic is also applicable to in-process background tasks. Ersetzen Sie jedoch anstelle der Run -Methode " onbackgroundaktivierte".But instead of the Run method, substitute OnBackgroundActivated. Hintergrundaufgaben innerhalb von Prozessen benötigen keinen beständigen Speicher, um den Abbruch zu signalisieren, da dieser mithilfe des App-Status übermittelt werden kann, wenn die Hintergrundaufgabe im selben Prozess ausgeführt wird, wie die Vordergrund-App.In-process background tasks do not require you to use persistent storage to signal the cancellation because you can communicate the cancellation using app state since the background task is running in the same process as your foreground app.

Verwenden der Methode „OnCanceled“ zum Erkennen von AbbruchanforderungenUse the OnCanceled method to recognize cancellation requests

Schreiben Sie eine Methode für die Behandlung des Abbruchereignisses.Write a method to handle the cancellation event.

Hinweis

Für alle Gerätefamilien mit Ausnahme von Desktops können Hintergrundaufgaben beendet werden, wenn der Arbeitsspeicher des Geräts knapp wird.For all device families except desktop, if the device becomes low on memory, background tasks may be terminated. Wenn keine Ausnahme wegen ungenügenden Arbeitsspeichers auftritt oder die APP Sie nicht verarbeitet, wird die Hintergrundaufgabe ohne Warnung und ohne das onabgeb Rochen-Ereignis beendet.If an out of memory exception is not surfaced, or the app doesn't handle it, then the background task will be terminated without warning and without raising the OnCanceled event. Dadurch soll die Benutzerfreundlichkeit der App im Vordergrund sichergestellt werden.This helps to ensure the user experience of the app in the foreground. Entwerfen Sie die Hintergrundaufgabe so, dass dieses Szenario behandelt werden kann.Your background task should be designed to handle this scenario.

Erstellen Sie eine Methode mit dem Namen onabgeb Rochen wie folgt.Create a method named OnCanceled as follows. Diese Methode ist der Einstiegspunkt, der von der Windows-Runtime aufgerufen wird, wenn eine Abbruchanforderung für die Hintergrundaufgabe erfolgt.This method is the entry point called by the Windows Runtime when a cancellation request is made against your background task.

private void OnCanceled(
    IBackgroundTaskInstance sender,
    BackgroundTaskCancellationReason reason)
{
    // TODO: Add code to notify the background task that it is cancelled.
}
void ExampleBackgroundTask::OnCanceled(
    Windows::ApplicationModel::Background::IBackgroundTaskInstance const& taskInstance,
    Windows::ApplicationModel::Background::BackgroundTaskCancellationReason reason)
{
    // TODO: Add code to notify the background task that it is cancelled.
}
void ExampleBackgroundTask::OnCanceled(
    IBackgroundTaskInstance^ taskInstance,
    BackgroundTaskCancellationReason reason)
{
    // TODO: Add code to notify the background task that it is cancelled.
}

Fügen Sie der Background-Aufgaben Klasse eine Flag-Variable namens ** _ cancelangeforderten** hinzu.Add a flag variable called _CancelRequested to the background task class. Diese Variable wird verwendet, um anzuzeigen, ob eine Abbruchanforderung erfolgt ist.This variable will be used to indicate when a cancellation request has been made.

volatile bool _CancelRequested = false;
private:
    volatile bool m_cancelRequested;
private:
    volatile bool CancelRequested;

Legen Sie in der OnCancel- Methode, die Sie in Schritt 1 erstellt haben, die Flag-Variable ** _ cancelangeforderten** auf truefest.In the OnCanceled method you created in step 1, set the flag variable _CancelRequested to true.

Die vollständige Hintergrundaufgaben-Beispiel Methode " ** _ OnCancel"** wird auf " true " festgelegt und schreibt eine potenziell nützliche Debugausgabe. OnCanceledThe full background task sample OnCanceled method sets _CancelRequested to true and writes potentially useful debug output.

private void OnCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
    // Indicate that the background task is canceled.
    _cancelRequested = true;

    Debug.WriteLine("Background " + sender.Task.Name + " Cancel Requested...");
}
void ExampleBackgroundTask::OnCanceled(
    Windows::ApplicationModel::Background::IBackgroundTaskInstance const& taskInstance,
    Windows::ApplicationModel::Background::BackgroundTaskCancellationReason reason)
{
    // Indicate that the background task is canceled.
    m_cancelRequested = true;
}
void ExampleBackgroundTask::OnCanceled(IBackgroundTaskInstance^ taskInstance, BackgroundTaskCancellationReason reason)
{
    // Indicate that the background task is canceled.
    CancelRequested = true;
}

Registrieren Sie in der Run -Methode der Hintergrundaufgabe die onabbrechen -Ereignishandlermethode, bevor Sie mit der Arbeit beginnen.In the background task's Run method, register the OnCanceled event handler method before starting work. Für eine Hintergrundaufgabe innerhalb von Prozessen empfiehlt sich diese Registrierung im Rahmen der Anwendungsinitialisierung.In an in-process background task, you might do this registration as part of your application initialization. Verwenden Sie z. b. die folgende Codezeile.For example, use the following line of code.

taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);
taskInstance.Canceled({ this, &ExampleBackgroundTask::OnCanceled });
taskInstance->Canceled += ref new BackgroundTaskCanceledEventHandler(this, &ExampleBackgroundTask::OnCanceled);

Behandeln des Abbruchs durch Beenden der HintergrundaufgabeHandle cancellation by exiting your background task

Wenn eine Abbruch Anforderung empfangen wird, muss Ihre Methode, die Hintergrundarbeit durchführt, die Arbeit beenden und den Vorgang beenden, indem Sie erkennt, wenn ** _ cancelangeforderten** auf truefestgelegt ist.When a cancellation request is received, your method that does background work needs to stop work and exit by recognizing when _cancelRequested is set to true. Für Prozess interne Hintergrundaufgaben bedeutet dies, dass von der onbackgroundaktivierten -Methode zurückgegeben wird.For in-process background tasks, this means returning from the OnBackgroundActivated method. Für Out-of-Process-Hintergrundaufgaben bedeutet dies, dass von der Run -Methode zurückgegeben wird.For out-of-process background tasks, this means returning from the Run method.

Ändern Sie den Code der Hintergrundaufgabenklasse, um die Kennzeichenvariable zu überprüfen, während die Hintergrundaufgabe ausgeführt wird.Modify the code of your background task class to check the flag variable while it's working. Wenn ** _ cancelangeforderten** auf true festgelegt wird, können Sie die Arbeit nicht fortsetzen.If _cancelRequested becomes set to true, stop work from continuing.

Das Beispiel für eine Hintergrundaufgabe schließt eine Prüfung ein, die den periodischen Zeit Geber Rückruf stoppt, wenn der Hintergrund Task abgebrochen wird.The background task sample includes a check that stops the periodic timer callback if the background task is canceled.

if ((_cancelRequested == false) && (_progress < 100))
{
    _progress += 10;
    _taskInstance.Progress = _progress;
}
else
{
    _periodicTimer.Cancel();
    // TODO: Record whether the task completed or was cancelled.
}
if (!m_cancelRequested && m_progress < 100)
{
    m_progress += 10;
    m_taskInstance.Progress(m_progress);
}
else
{
    m_periodicTimer.Cancel();
    // TODO: Record whether the task completed or was cancelled.
}
if ((CancelRequested == false) && (Progress < 100))
{
    Progress += 10;
    TaskInstance->Progress = Progress;
}
else
{
    PeriodicTimer->Cancel();
    // TODO: Record whether the task completed or was cancelled.
}

Hinweis

Das oben gezeigte Codebeispiel verwendet die ibackgroundtaskinstance. Fortschritts Eigenschaft, die verwendet wird, um den Fortschritt des Hintergrund Tasks aufzuzeichnenThe code sample shown above uses the IBackgroundTaskInstance.Progress property being used to record background task progress. Der Fortschritt wird der App mithilfe der BackgroundTaskProgressEventArgs-Klasse gemeldet.Progress is reported back to the app using the BackgroundTaskProgressEventArgs class.

Ändern Sie die Run -Methode so, dass nach dem Beenden der Arbeit aufgezeichnet wird, ob die Aufgabe abgeschlossen oder abgebrochen wurde.Modify the Run method so that after work has stopped, it records whether the task completed or was cancelled. Dieser Schritt gilt für Hintergrundaufgaben außerhalb von Prozessen, da eine Möglichkeit für die Kommunikation zwischen Prozessen haben müssen, wenn die Hintergrundaufgabe abgebrochen wurde.This step applies to out-of-process background tasks because you need a way to communicate between processes when the background task was cancelled. Für Hintergrundaufgaben innerhalb von Prozessen können Sie den Status einfach mit der Anwendung teilen, um anzugeben, dass die Aufgabe abgebrochen wurde.For in-process background tasks, you can simply share state with the application to indicate the task was cancelled.

Im Hintergrundaufgaben Beispiel wird der Status in LocalSettings aufgezeichnet.The background task sample records status in LocalSettings.

if ((_cancelRequested == false) && (_progress < 100))
{
    _progress += 10;
    _taskInstance.Progress = _progress;
}
else
{
    _periodicTimer.Cancel();

    var settings = ApplicationData.Current.LocalSettings;
    var key = _taskInstance.Task.TaskId.ToString();

    // Write to LocalSettings to indicate that this background task ran.
    if (_cancelRequested)
    {
        settings.Values[key] = "Canceled";
    }
    else
    {
        settings.Values[key] = "Completed";
    }
        
    Debug.WriteLine("Background " + _taskInstance.Task.Name + (_cancelRequested ? " Canceled" : " Completed"));
        
    // Indicate that the background task has completed.
    _deferral.Complete();
}
if (!m_cancelRequested && m_progress < 100)
{
    m_progress += 10;
    m_taskInstance.Progress(m_progress);
}
else
{
    m_periodicTimer.Cancel();

    // Write to LocalSettings to indicate that this background task ran.
    auto settings{ Windows::Storage::ApplicationData::Current().LocalSettings() };
    auto key{ m_taskInstance.Task().Name() };
    settings.Values().Insert(key, (m_progress < 100) ? winrt::box_value(L"Canceled") : winrt::box_value(L"Completed"));

    // Indicate that the background task has completed.
    m_deferral.Complete();
}
if ((CancelRequested == false) && (Progress < 100))
{
    Progress += 10;
    TaskInstance->Progress = Progress;
}
else
{
    PeriodicTimer->Cancel();
        
    // Write to LocalSettings to indicate that this background task ran.
    auto settings = ApplicationData::Current->LocalSettings;
    auto key = TaskInstance->Task->Name;
    settings->Values->Insert(key, (Progress < 100) ? "Canceled" : "Completed");
        
    // Indicate that the background task has completed.
    Deferral->Complete();
}

BemerkungenRemarks

Sie können das Beispiel zur Hintergrundaufgabe herunterladen, um diese Codebeispiele im Kontext von Methoden anzuzeigen.You can download the background task sample to see these code examples in the context of methods.

Zu Veranschaulichung zeigt der Beispielcode nur Teile der Run -Methode (und des Rückruf Timers) aus dem Hintergrundaufgaben Beispiel.For illustrative purposes, the sample code shows only portions of the Run method (and callback timer) from the background task sample.

Beispiel der Run-MethodeRun method example

Die gesamte Ausführungs Methode und der Timer-Rückruf Code aus dem Hintergrundaufgaben Beispiel sind unten für den Kontext dargestellt.The complete Run method, and timer callback code, from the background task sample are shown below for context.

// The Run method is the entry point of a background task.
public void Run(IBackgroundTaskInstance taskInstance)
{
    Debug.WriteLine("Background " + taskInstance.Task.Name + " Starting...");

    // Query BackgroundWorkCost
    // Guidance: If BackgroundWorkCost is high, then perform only the minimum amount
    // of work in the background task and return immediately.
    var cost = BackgroundWorkCost.CurrentBackgroundWorkCost;
    var settings = ApplicationData.Current.LocalSettings;
    settings.Values["BackgroundWorkCost"] = cost.ToString();

    // Associate a cancellation handler with the background task.
    taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);

    // Get the deferral object from the task instance, and take a reference to the taskInstance;
    _deferral = taskInstance.GetDeferral();
    _taskInstance = taskInstance;

    _periodicTimer = ThreadPoolTimer.CreatePeriodicTimer(new TimerElapsedHandler(PeriodicTimerCallback), TimeSpan.FromSeconds(1));
}

// Simulate the background task activity.
private void PeriodicTimerCallback(ThreadPoolTimer timer)
{
    if ((_cancelRequested == false) && (_progress < 100))
    {
        _progress += 10;
        _taskInstance.Progress = _progress;
    }
    else
    {
        _periodicTimer.Cancel();

        var settings = ApplicationData.Current.LocalSettings;
        var key = _taskInstance.Task.Name;

        // Write to LocalSettings to indicate that this background task ran.
        settings.Values[key] = (_progress < 100) ? "Canceled with reason: " + _cancelReason.ToString() : "Completed";
        Debug.WriteLine("Background " + _taskInstance.Task.Name + settings.Values[key]);

        // Indicate that the background task has completed.
        _deferral.Complete();
    }
}
void ExampleBackgroundTask::Run(Windows::ApplicationModel::Background::IBackgroundTaskInstance const& taskInstance)
{
    // Query BackgroundWorkCost
    // Guidance: If BackgroundWorkCost is high, then perform only the minimum amount
    // of work in the background task and return immediately.
    auto cost{ Windows::ApplicationModel::Background::BackgroundWorkCost::CurrentBackgroundWorkCost() };
    auto settings{ Windows::Storage::ApplicationData::Current().LocalSettings() };
    std::wstring costAsString{ L"Low" };
    if (cost == Windows::ApplicationModel::Background::BackgroundWorkCostValue::Medium) costAsString = L"Medium";
    else if (cost == Windows::ApplicationModel::Background::BackgroundWorkCostValue::High) costAsString = L"High";
    settings.Values().Insert(L"BackgroundWorkCost", winrt::box_value(costAsString));

    // Associate a cancellation handler with the background task.
    taskInstance.Canceled({ this, &ExampleBackgroundTask::OnCanceled });

    // Get the deferral object from the task instance, and take a reference to the taskInstance.
    m_deferral = taskInstance.GetDeferral();
    m_taskInstance = taskInstance;

    Windows::Foundation::TimeSpan period{ std::chrono::seconds{1} };
    m_periodicTimer = Windows::System::Threading::ThreadPoolTimer::CreatePeriodicTimer([this](Windows::System::Threading::ThreadPoolTimer timer)
    {
        if (!m_cancelRequested && m_progress < 100)
        {
            m_progress += 10;
            m_taskInstance.Progress(m_progress);
        }
        else
        {
            m_periodicTimer.Cancel();

            // Write to LocalSettings to indicate that this background task ran.
            auto settings{ Windows::Storage::ApplicationData::Current().LocalSettings() };
            auto key{ m_taskInstance.Task().Name() };
            settings.Values().Insert(key, (m_progress < 100) ? winrt::box_value(L"Canceled") : winrt::box_value(L"Completed"));

            // Indicate that the background task has completed.
            m_deferral.Complete();
        }
    }, period);
}
void ExampleBackgroundTask::Run(IBackgroundTaskInstance^ taskInstance)
{
    // Query BackgroundWorkCost
    // Guidance: If BackgroundWorkCost is high, then perform only the minimum amount
    // of work in the background task and return immediately.
    auto cost = BackgroundWorkCost::CurrentBackgroundWorkCost;
    auto settings = ApplicationData::Current->LocalSettings;
    settings->Values->Insert("BackgroundWorkCost", cost.ToString());

    // Associate a cancellation handler with the background task.
    taskInstance->Canceled += ref new BackgroundTaskCanceledEventHandler(this, &ExampleBackgroundTask::OnCanceled);

    // Get the deferral object from the task instance, and take a reference to the taskInstance.
    TaskDeferral = taskInstance->GetDeferral();
    TaskInstance = taskInstance;

    auto timerDelegate = [this](ThreadPoolTimer^ timer)
    {
        if ((CancelRequested == false) &&
            (Progress < 100))
        {
            Progress += 10;
            TaskInstance->Progress = Progress;
        }
        else
        {
            PeriodicTimer->Cancel();

            // Write to LocalSettings to indicate that this background task ran.
            auto settings = ApplicationData::Current->LocalSettings;
            auto key = TaskInstance->Task->Name;
            settings->Values->Insert(key, (Progress < 100) ? "Canceled with reason: " + CancelReason.ToString() : "Completed");

            // Indicate that the background task has completed.
            TaskDeferral->Complete();
        }
    };

    TimeSpan period;
    period.Duration = 1000 * 10000; // 1 second
    PeriodicTimer = ThreadPoolTimer::CreatePeriodicTimer(ref new TimerElapsedHandler(timerDelegate), period);
}