Flutter:调用新循环时终止旧循环的实现方案
解决重复调用异步任务时终止旧任务的问题
要实现"旧循环未完成时调用doSomething()就终止旧循环并启动新循环"的需求,核心是把同步的网络请求流程改成异步管理,并加入取消机制,具体实现如下:
方案1:基础实现(不依赖第三方包)
通过维护取消标记和当前任务的引用,手动终止旧循环:
class SongClass { List songs = [ {'id': 1, 'name': 'Song 1'}, {'id': 2, 'name': 'Song 2'}, // 更多歌曲数据 ]; List otherSongs = []; bool _isCancelled = false; Future<void>? _currentTask; Future<void> doSomething() async { // 先终止正在进行的旧任务 if (_currentTask != null) { _isCancelled = true; await _currentTask; // 等待旧任务彻底结束 _isCancelled = false; } otherSongs.clear(); _currentTask = _processSongs(); await _currentTask; _currentTask = null; } Future<void> _processSongs() async { for (var item in songs) { // 每次循环前检查是否被取消,直接退出 if (_isCancelled) return; // 替换成你的实际网络请求逻辑 final songDetail = await _fetchSongDetail(item); // 请求完成后再次检查,避免取消后仍添加数据 if (!_isCancelled) { otherSongs.add(songDetail); } } } // 模拟网络请求,实际替换成你的API调用 Future<Map> _fetchSongDetail(Map song) async { await Future.delayed(const Duration(milliseconds: 500)); return {...song, 'detail': 'Fetched detail for ${song['name']}'}; } }
关键逻辑说明:
_isCancelled:标记当前任务是否需要终止,新调用doSomething()时会将其设为true,旧循环检测到后直接退出。_currentTask:跟踪当前正在执行的异步任务,确保旧任务完全终止后再启动新任务,避免状态混乱。- 两次检查取消标记:循环开始前检查避免无效请求,请求完成后检查避免取消后仍修改
otherSongs。
方案2:结合http包的高效实现(推荐)
如果你的网络请求使用http包,可以用自带的CancelToken直接终止网络请求,比单纯标记取消更高效:
import 'package:http/http.dart' as http; import 'dart:convert'; class SongClass { List songs = [ {'id': 1, 'name': 'Song 1'}, {'id': 2, 'name': 'Song 2'}, // 更多歌曲数据 ]; List otherSongs = []; http.CancelToken? _currentCancelToken; Future<void>? _currentTask; Future<void> doSomething() async { // 取消当前的网络请求和任务 if (_currentCancelToken != null) { _currentCancelToken!.cancel('New task started'); await _currentTask; _currentCancelToken = null; } otherSongs.clear(); _currentCancelToken = http.CancelToken(); _currentTask = _processSongs(_currentCancelToken!); await _currentTask; _currentTask = null; _currentCancelToken = null; } Future<void> _processSongs(http.CancelToken cancelToken) async { for (var item in songs) { if (cancelToken.isCancelled) return; try { // 实际API请求,传入CancelToken支持取消 final response = await http.get( Uri.parse('https://your-api-url/songs/${item['id']}/detail'), cancelToken: cancelToken, ); if (cancelToken.isCancelled) return; // 解析响应数据 final songDetail = jsonDecode(response.body); otherSongs.add({...item, ...songDetail}); } on http.CancelException { // 捕获请求取消异常,直接退出 return; } catch (e) { // 处理其他网络错误 print('Fetch error: $e'); } } } }
关键逻辑说明:
CancelToken:http包提供的令牌,调用cancel()可以直接终止正在进行的网络请求,无需等待请求完成。- 捕获
CancelException:网络请求被取消时会抛出该异常,直接退出循环即可。
内容的提问来源于stack exchange,提问作者Sheikh Haziq
相关产品推荐
相关产品推荐

