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

如何用ProgressIndicator展示Isolate中异步任务的进度?

在Flutter Isolate中实现进度更新的正确方式

Isolate之间内存完全隔离,不能直接传递回调函数,必须通过消息传递机制(SendPort/ReceivePort)实现主Isolate(UI线程)和子Isolate的通信。下面是修改后的完整代码,实现进度实时更新:

import 'package:flutter/material.dart';
import 'dart:isolate';

class IsolateProgress extends StatefulWidget {
  const IsolateProgress({super.key});

  @override
  State<IsolateProgress> createState() => _IsolateProgressState();
}

class _IsolateProgressState extends State<IsolateProgress> {
  double _progress = 0.0;
  Map<int, bool>? _results;
  Isolate? _isolate;
  final ReceivePort _receivePort = ReceivePort();

  @override
  void initState() {
    super.initState();
    _startHeavyTask();
  }

  void _startHeavyTask() async {
    final List<int> listToCheck = [1, 11, 111, 1111, 11111, 96953, 111111, 99971, 11111111, 999999487];
    
    // 监听子Isolate发来的消息
    _receivePort.listen((message) {
      if (message is double) {
        // 更新进度
        setState(() => _progress = message);
      } else if (message is Map<int, bool>) {
        // 任务完成,接收结果
        setState(() => _results = message);
        // 关闭资源
        _receivePort.close();
        _isolate?.kill(priority: Isolate.immediate);
      }
    });

    // 手动创建Isolate,传入SendPort和任务参数
    _isolate = await Isolate.spawn(
      _heavyTask,
      _TaskParams(
        sendPort: _receivePort.sendPort,
        listToCheck: listToCheck,
      ),
    );
  }

  @override
  void dispose() {
    _receivePort.close();
    _isolate?.kill(priority: Isolate.immediate);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Isolate Progress')),
      body: _buildContent(),
    );
  }

  Widget _buildContent() {
    if (_results != null) {
      return ListView(
        children: _results!.entries
            .map((e) => Padding(
                  padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
                  child: Text('${e.key}: ${e.value ? '是质数' : '不是质数'}'),
                ))
            .toList(),
      );
    }

    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          CircularProgressIndicator(value: _progress),
          const SizedBox(height: 16),
          Text('进度: ${(_progress * 100).toStringAsFixed(1)}%'),
        ],
      ),
    );
  }
}

// 用于传递给Isolate的参数类(必须是可序列化的)
class _TaskParams {
  final SendPort sendPort;
  final List<int> listToCheck;

  _TaskParams({required this.sendPort, required this.listToCheck});
}

// 子Isolate执行的任务(必须是顶层函数或static函数)
void _heavyTask(_TaskParams params) {
  final SendPort sendPort = params.sendPort;
  final List<int> listToCheck = params.listToCheck;
  final Map<int, bool> result = {};
  final int total = listToCheck.length;

  for (int index = 0; index < total; index++) {
    final int num = listToCheck[index];
    
    // 模拟异步延迟(实际业务中替换为真实重型任务)
    Future.delayed(const Duration(milliseconds: 100)).then((_) {
      if (num == 1) {
        result[num] = false;
      } else {
        result[num] = true;
        for (int i = 2; i * i <= num; i++) { // 优化质数判断逻辑,减少循环次数
          if (num % i == 0) {
            result[num] = false;
            break;
          }
        }
      }

      // 计算进度并发送给主Isolate
      final double progress = (index + 1) / total;
      sendPort.send(progress);

      // 所有任务完成后发送结果
      if (index == total - 1) {
        sendPort.send(result);
      }
    });
  }
}

关键说明:

  • 必须使用StatefulWidget:需要维护进度和结果的状态,触发UI更新。
  • 消息传递机制:通过ReceivePort监听子Isolate消息,SendPort实现子Isolate向主Isolate发送进度、结果数据。
  • 参数序列化:传递给Isolate的参数必须可序列化,这里用_TaskParams封装避免传递非序列化对象。
  • 资源清理:在页面销毁或任务完成时关闭端口、销毁Isolate,防止内存泄漏。
  • 任务优化:将质数判断的循环条件改为i * i <= num,大幅减少计算量。

内容的提问来源于stack exchange,提问作者Florian

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 13:43:16