如何取消任务C# [英] How to cancel Task C#

查看:311
本文介绍了如何取消任务C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个任务,可以从Web服务检索一些数据.仅当我打开页面(即Xamarin.Forms)时,Web服务才应被调用,并且仅当没有其他版本的任务正在运行时,Web服务才应运行-这部分工作正常.

I have a Task which retrieves some data from a Web Service. The Webservice should only get called when I open a page (this is Xamarin.Forms) and it should only run if there isn't another version of the task running - This part works fine.

当我离开页面时,我想取消任务-我似乎无法使该任务正常工作.当OnAppearing()OnDisappearing()OnAppearing() is hit before the webservice returns the data, logs just write "Task has attempted to start..." which means that the Task didn't get cancelled. Instead the task should have been cancelled when OnDisappearing()`被调用时.

When I move away from the page, I want to cancel the Task - I can't seem to get that piece working. When OnAppearing(), OnDisappearing(), OnAppearing() is hit before the webservice returns the data, logs just write "Task has attempted to start..." which means that the Task didn't get cancelled. Instead the task should have been cancelled whenOnDisappearing()` was called.

我尝试遵循在StackOverflow上发布的一些示例,但似乎无法正常工作,我无法弄清楚.

I have tried to follow some of the examples posted on StackOverflow but doesn't seem to work and I can't quite figure it out.

我的代码如下:

出现:

private Task task;
CancellationTokenSource tokenSource = new CancellationTokenSource();

protected override void OnAppearing()
{
    base.OnAppearing();

    if (task != null && (task.Status == TaskStatus.Running || task.Status == TaskStatus.WaitingToRun || task.Status == TaskStatus.WaitingForActivation))
    {
        Debug.WriteLine("Task has attempted to start while already running");
    }
    else
    {
        Debug.WriteLine("Task has began");

        var token = tokenSource.Token;
        task = Task.Run(async () =>
        {

            await GetDataAsync();
            /* EDIT: This is what I originally posted, but doesn't work so have commented it out
            while (!token.IsCancellationRequested)
            {
                await GetDataAsync();
            }
             */
       }, token);
   }      
}

消失中:

protected override void OnDisappearing()
{
    base.OnDisappearing();
    Debug.WriteLine("Page dissapear");
    tokenSource.Cancel();
    Debug.WriteLine("Task Cancelled");
}

GetData方法

public async Task GetData()
{
    WebAPI api = new WebAPI();

    try
    {
        Device.BeginInvokeOnMainThread(() =>
        {
            PageLoading();
        });

        string r = await api.GetProfileStatus(token);
        Device.BeginInvokeOnMainThread(async () =>
        {
           if (r == "OK")
           {
                GetDataSuccess();
           }
        }
     }
     catch (Exception e)
     {
        // log exception
     }
}

推荐答案

您在错误的位置进行了正确的检查:

You're doing the right check in a wrong place:

var token = tokenSource.Token;
task = Task.Run(async () =>
{
    while (!token.IsCancellationRequested)
    {
        await GetDataAsync();
    }
}

在这里启动任务,然后在循环中一次又一次地启动它.正确的做法是检查GetData中的令牌,并在可能的情况下进一步访问api变量.在这种情况下,您可以根据需要取消服务呼叫.

Here you start the task, and after that start it again and again in a loop. The right thing to do is check the token inside your GetData, and futher to api variable, if possible. In this case you'll be able to cancel the service call as you need.

旁注:

  • 将事件处理程序设置为async,并且不要将工作包装在Task.Run
  • 设置您的GetData Task<T>,以便您实际上可以将状态返回到调用代码,然后可以删除BeginInvokeOnMainThread,因为await将在异步操作后恢复上下文
  • make your event handlers async, and do not wrap your work in Task.Run
  • make your GetData Task<T> so you can actually return status to the calling code, then you can remove BeginInvokeOnMainThread, as await will restore the context after async operation

因此您的代码将如下所示:

So your code will be something like this:

protected override async void OnAppearing()
{
    base.OnAppearing();

    if (task != null && (task.Status == TaskStatus.Running || task.Status == TaskStatus.WaitingToRun || task.Status == TaskStatus.WaitingForActivation))
    {
        Debug.WriteLine("Task has attempted to start while already running");
    }
    else
    {
        Debug.WriteLine("Task has began");

        var token = tokenSource.Token;
        PageLoading();
        var r = await GetDataAsync(token);
        if (r == "OK")
        {
            GetDataSuccess();
        }
   }      
}

public async Task GetDataAsync(CancellationToken token)
{
    WebAPI api = new WebAPI();
    if (token.IsCancellationRequested)
    {
        token.ThrowIfCancellationRequested();
    }

    try
    {
        return await api.GetProfileStatus(token);
    }
    catch (Exception e)
    {
        // log exception and return error
        return "Error";
    }
}

这篇关于如何取消任务C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆