Gérer une tâche en arrière-plan annuléeHandle a cancelled background task

API importantesImportant APIs

Découvrez comment créer une tâche en arrière-plan qui reconnaît une demande d’annulation, arrête le travail et signale l’annulation à l’application en utilisant le dispositif de stockage persistant.Learn how to make a background task that recognizes a cancellation request, stops work, and reports the cancellation to the app using persistent storage.

Cette rubrique suppose que vous avez déjà créé une classe de tâche en arrière-plan, y compris la méthode Run utilisée comme le point d’entrée de tâche en arrière-plan.This topic assumes you have already created a background task class, including the Run method that is used as the background task entry point. Pour commencer rapidement à créer une tâche en arrière-plan, consultez Créer et inscrire une tâche en arrière-plan hors processus ou Créer et inscrire une tâche en arrière-plan in-process.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. Pour des informations plus détaillées sur les conditions et les déclencheurs, voir Définition de tâches en arrière-plan pour les besoins de votre application.For more in-depth information on conditions and triggers, see Support your app with background tasks.

Cette rubrique s’applique également aux tâches en arrière-plan in-process.This topic is also applicable to in-process background tasks. Mais au lieu de la méthode Run , remplacez OnBackgroundActivated.But instead of the Run method, substitute OnBackgroundActivated. Pour les tâches en arrière-plan in-process, il n’est pas nécessaire d’utiliser un dispositif de stockage persistant pour signaler l’annulation. En effet, vous pouvez signaler l’annulation via le paramètre d’état de l’application, car la tâche en arrière-plan s’exécute dans le même processus que votre application au premier plan.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.

Utiliser la méthode OnCanceled pour reconnaître les demandes d’annulationUse the OnCanceled method to recognize cancellation requests

Écrivez une méthode permettant de gérer l’événement d’annulation.Write a method to handle the cancellation event.

Note

Pour toutes les familles d’appareils, à l’exception des ordinateurs de bureau, les tâches en arrière-plan peuvent être arrêtées en cas de mémoire insuffisante de l’appareil.For all device families except desktop, if the device becomes low on memory, background tasks may be terminated. Si une exception de mémoire insuffisante n’est exposée ou si l’application ne gère pas, la tâche en arrière-plan est alors arrêtée sans avertissement ni déclenchement de l’événement OnCanceled.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. Cela permet de garantir l’expérience utilisateur de l’application au premier plan.This helps to ensure the user experience of the app in the foreground. Votre tâche en arrière-plan doit être conçue de manière à gérer ce scénario.Your background task should be designed to handle this scenario.

Créez une méthode nommée OnCanceled en procédant comme suit.Create a method named OnCanceled as follows. Cette méthode constitue le point d’entrée appelé par Windows Runtime lorsqu’une demande d’annulation est formulée pour votre tâche en arrière-plan.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.
}

Ajoutez une variable d’indicateur appelée _CancelRequested à la classe de tâche en arrière-plan.Add a flag variable called _CancelRequested to the background task class. Cette variable servira à indiquer qu’une demande d’annulation a été effectuée.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;

Dans la méthode OnCanceled que vous avez créé à l’étape 1, définissez la variable indicateur _CancelRequested sur true.In the OnCanceled method you created in step 1, set the flag variable _CancelRequested to true.

L' complet exemple de tâche en arrière-plan , méthode OnCanceled définit _CancelRequested sur true et écrit la sortie de débogage peuvent se révéler utiles.The 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;
}

Dans la méthode Run de la tâche en arrière-plan, inscrivez la méthode de gestionnaire d’événements OnCanceled avant de commencer à travailler.In the background task's Run method, register the OnCanceled event handler method before starting work. Dans le cas d’une tâche en arrière-plan in-process, vous pouvez effectuer cette inscription dans le cadre de l’initialisation de votre application.In an in-process background task, you might do this registration as part of your application initialization. Par exemple, utilisez la ligne de code suivante.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);

Gérer une annulation en fermant votre tâche en arrière-planHandle cancellation by exiting your background task

Lors de la réception d’une demande d’annulation, la méthode qui effectue la tâche en arrière-plan doit arrêter le travail et se fermer en reconnaissant que _cancelRequested est défini sur la valeur true.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. Pour les tâches en arrière-plan in-process, cela implique un retour à partir de la méthode OnBackgroundActivated .For in-process background tasks, this means returning from the OnBackgroundActivated method. Pour les tâches en arrière-plan out-of-process, cela implique un retour à partir de la méthode Run .For out-of-process background tasks, this means returning from the Run method.

Modifiez le code de votre classe de tâche en arrière-plan pour vérifier la variable d’indicateur pendant qu’elle est utilisée.Modify the code of your background task class to check the flag variable while it's working. Si _cancelRequested devient défini sur true, arrêter le travail de continuer.If _cancelRequested becomes set to true, stop work from continuing.

L' exemple de tâche en arrière-plan comprend une vérification qui arrête le rappel de minuteur périodique en cas d’annulation de la tâche en arrière-plan.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.
}

Note

L’exemple de code présenté ci-dessus utilise IBackgroundTaskInstance. Propriété de progression qui sert à enregistrer la progression de la tâche en arrière-plan.The code sample shown above uses the IBackgroundTaskInstance.Progress property being used to record background task progress. La progression est indiquée à l’application à l’aide de la classe BackgroundTaskProgressEventArgs.Progress is reported back to the app using the BackgroundTaskProgressEventArgs class.

Modifiez la méthode Run de sorte qu’une fois le travail arrêté, elle enregistre si la tâche terminée ou a été annulée.Modify the Run method so that after work has stopped, it records whether the task completed or was cancelled. Cette étape s’applique aux tâches en arrière-plan hors processus, car vous avez besoin d’un moyen pour communiquer entre les processus lorsque la tâche en arrière-plan a été annulée.This step applies to out-of-process background tasks because you need a way to communicate between processes when the background task was cancelled. Pour les tâches en arrière-plan in-process, vous pouvez simplement partager l’état avec l’application pour indiquer que la tâche a été annulée.For in-process background tasks, you can simply share state with the application to indicate the task was cancelled.

L' exemple de tâche en arrière-plan enregistre l’état dans LocalSettings.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();
}

RemarquesRemarks

Vous pouvez télécharger l’exemple de tâche en arrière-plan pour voir ces exemples de code dans le contexte des méthodes.You can download the background task sample to see these code examples in the context of methods.

À des fins d’illustration, l’exemple de code présente uniquement des portions de la méthode Run (et le minuteur de rappel) à partir de l' exemple de tâche en arrière-plan.For illustrative purposes, the sample code shows only portions of the Run method (and callback timer) from the background task sample.

Exemple de méthode RunRun method example

La terminer méthode Run et le code de rappel de minuteur, à partir de l' exemple de tâche en arrière-plan sont présentés ci-dessous pour le contexte.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);
}