You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 11:45:34