c# - C# 如何取消任务

标签 c# xamarin.forms async-await task-parallel-library cancellation

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

当我离开页面时,我想取消任务 - 我似乎无法让该部分工作。当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()` 被调用。

我尝试遵循 StackOverflow 上发布的一些示例,但似乎不起作用,而且我不太明白。

我的代码如下:

出现时:

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

获取数据方法

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

最佳答案

您在错误的地方进行了正确的检查:

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

在这里启动任务,然后循环启动它。正确的做法是检查 GetData 内的 token ,并进一步到api变量,如果可能的话。在这种情况下,您可以根据需要取消服务调用。

旁注:

  • 创建您的事件处理程序 async ,并且不要将您的工作包装在 Task.Run
  • 让你的GetData Task<T>所以你实际上可以将状态返回给调用代码,然后你可以删除 BeginInvokeOnMainThread ,如await将在异步操作后恢复上下文

所以你的代码将是这样的:

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# - C# 如何取消任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49499495/

相关文章:

c# - 带有 OAuth2 的 Youtube API v3 返回 "Received verification code. Closing..."

c# - 有没有办法为 VS2017 即时创建 TestMethods?

ios - 物理尺寸 Iphone XS Max 和 Iphone XR 屏幕

javascript - 我必须等待 void 异步函数吗?

c# - 异步等待一个简单的包装方法

c# - Entity Framework 未获取复杂类型的列

c# - 根据对父项的引用将项添加到列表

android - 如何在 Android 上的 Xamarin.Forms 中的 NavigationBar 左侧添加 ToolbarItem?

user-interface - Xamarin表单框架未随内容扩展

javascript - 在异步上下文之外尝试/捕获异步函数