如何在Xamarin.Forms中取消Task?C#任务取消技术咨询
我明白你现在遇到的麻烦了——页面切换时Web Service的Task没法被正确取消,导致快速进出页面后任务直接卡住,只弹出“Task has attempted to start...”的日志对吧?这种场景在Xamarin.Forms里确实容易踩坑,我来给你捋捋怎么解决。
核心问题分析
你看到的日志说明:当你快速触发OnAppearing()→OnDisappearing()→OnAppearing()时,旧的Web Service任务并没有真正被取消,它的状态还是“运行中”,所以被你之前做的「同版本任务唯一性」逻辑拦截了,导致新任务无法启动。
具体解决方案
1. 给页面绑定专属的取消令牌源
首先要把CancellationTokenSource的生命周期和页面绑定,确保每次进入页面都用新的令牌,离开页面时立刻取消并释放旧令牌:
// 在页面类里声明专属的取消令牌源 private CancellationTokenSource _pageCts; protected override void OnAppearing() { base.OnAppearing(); // 每次进入页面都创建全新的Cts,避免旧取消信号干扰 _pageCts = new CancellationTokenSource(); // 传入令牌启动任务 _ = FetchWebServiceDataAsync(_pageCts.Token); } protected override void OnDisappearing() { base.OnDisappearing(); // 取消任务+释放资源,避免内存泄漏 _pageCts?.Cancel(); _pageCts?.Dispose(); _pageCts = null; }
2. 在任务逻辑里主动响应取消信号
光调用Cancel()没用,必须在Web Service的执行流程里关键节点检查取消令牌,让任务能立刻终止:
private async Task FetchWebServiceDataAsync(CancellationToken cancellationToken) { // 先检查是否已取消,直接终止无效执行 cancellationToken.ThrowIfCancellationRequested(); try { using var client = new HttpClient(); // 把令牌传给HttpClient,让请求本身也能响应取消 var response = await client.GetAsync("你的Web Service接口地址", cancellationToken); // 请求返回后再次检查,避免等待期间已触发取消 cancellationToken.ThrowIfCancellationRequested(); // 处理返回数据(比如更新UI) var data = await response.Content.ReadAsStringAsync(cancellationToken); // ...你的数据解析和UI更新逻辑 } catch (OperationCanceledException) { // 任务被取消时的日志或处理 Console.WriteLine("Web Service任务已被正常取消"); } catch (Exception ex) { // 其他异常处理 Console.WriteLine($"请求出错:{ex.Message}"); } }
3. 让任务唯一性逻辑兼容取消状态
你之前的「无同版本任务运行才执行」逻辑要补充判断任务是否已被取消,不然旧任务卡在取消流程里时,新任务还是会被拦截:
// 跟踪当前运行的任务 private Task _currentDataTask; private async Task FetchWebServiceDataAsync(CancellationToken cancellationToken) { // 检查当前任务是否处于有效运行状态(未完成、未取消、未出错) if (_currentDataTask != null && !_currentDataTask.IsCompleted && !_currentDataTask.IsCanceled && !_currentDataTask.IsFaulted) { Console.WriteLine("Task has attempted to start..."); return; } try { // 把实际请求逻辑抽出来,方便跟踪任务状态 _currentDataTask = ExecuteWebServiceCallAsync(cancellationToken); await _currentDataTask; } finally { // 不管任务是完成、取消还是出错,都重置跟踪字段 _currentDataTask = null; } } // 实际执行Web Service调用的方法 private async Task ExecuteWebServiceCallAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); using var client = new HttpClient(); var response = await client.GetAsync("你的Web Service接口地址", cancellationToken); cancellationToken.ThrowIfCancellationRequested(); var data = await response.Content.ReadAsStringAsync(cancellationToken); // ...数据处理逻辑 }
验证效果
当你快速切换页面时:
- 第一次
OnAppearing()启动任务 OnDisappearing()触发取消,任务里的ThrowIfCancellationRequested()会抛出异常,任务进入「已取消」状态- 第二次
OnAppearing()时,_currentDataTask已经是「已取消」状态,唯一性逻辑会允许新任务启动,不会再弹出那个拦截日志
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

