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

Flutter Isolate旋转图片报错:非法参数无法发送对象

问题原因及解决方案

异常根源

你遇到的Invalid argument(s): Illegal argument in isolate message异常,核心是Isolate间消息传递的逻辑完全混乱,导致不可序列化的_AsyncCompleter对象被卷入消息传递流程。具体问题如下:

  1. 主Isolate没给子Isolate发图片数据
    子Isolate启动后一直在等图片的Uint8List,但你的rotateImage函数里,主Isolate只启动了子Isolate,从来没把foto(图片字节)传过去,子Isolate根本没机会执行旋转逻辑。

  2. 错误把SendPort当成结果给了Completer
    子Isolate启动后会先把自己的ReceivePort.sendPort发回主Isolate,主Isolate的receivePort.listen第一次收到的就是这个SendPort。你直接用这个SendPort完成了Completer,而Completer原本要接收的是Uint8List。这种错误的类型匹配,加上Completer内部的异步状态对象不可跨Isolate传递,直接触发了异常。

  3. ReceivePort关得太早
    主Isolate刚收到子Isolate的SendPort就关闭了自己的ReceivePort,就算子Isolate后来能处理图片,也没法把结果发回来。

修正后的代码

import 'dart:async';
import 'dart:isolate';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image/image.dart' as img;

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

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  Uint8List? foto;

  Future<void> loadImage() async {
    final ByteData data = await rootBundle.load('assets/images/IMG_4510.HEIC');
    setState(() {
      foto = data.buffer.asUint8List();
    });
  }

  static void _rotateIsolate(SendPort mainSendPort) {
    final ReceivePort childReceivePort = ReceivePort();
    // 把子Isolate的SendPort传给主Isolate,后续用来传数据和结果
    mainSendPort.send(childReceivePort.sendPort);

    childReceivePort.listen((dynamic data) {
      if (data is Uint8List) {
        // 执行旋转操作
        final img.Image image = img.decodeImage(data)!;
        final img.Image rotatedImage = img.copyRotate(image, angle: 90);
        final Uint8List result = Uint8List.fromList(img.encodePng(rotatedImage));
        // 把结果发回主Isolate
        mainSendPort.send(result);
        childReceivePort.close();
      }
    });
  }

  Future<void> rotateImage() async {
    if (foto == null) return;

    final ReceivePort mainReceivePort = ReceivePort();
    // 启动子Isolate,传入主Isolate的SendPort
    await Isolate.spawn(_rotateIsolate, mainReceivePort.sendPort);

    late SendPort childSendPort;
    final completer = Completer<Uint8List>();

    mainReceivePort.listen((message) {
      if (message is SendPort) {
        // 第一次收到子Isolate的SendPort,现在可以发图片数据了
        childSendPort = message;
        childSendPort.send(foto);
      } else if (message is Uint8List) {
        // 收到旋转后的图片,完成Completer并关闭端口
        completer.complete(message);
        mainReceivePort.close();
      }
    });

    // 更新UI
    final rotatedBytes = await completer.future;
    setState(() {
      foto = rotatedBytes;
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            foto != null
                ? Image.memory(foto!)
                : const CircularProgressIndicator(),
            ElevatedButton(
              onPressed: rotateImage,
              child: const Text('Rotate'),
            )
          ],
        ),
      ),
    );
  }
}

关键修正说明

  • 图片加载逻辑优化:把图片加载放到initState里,直接更新foto状态,不用FutureBuilder绕一圈。
  • 规范Isolate通信流程:
    1. 主Isolate启动子Isolate时,传自己的SendPort。
    2. 子Isolate先把自己的SendPort发回主Isolate,建立双向通信通道。
    3. 主Isolate拿到子Isolate的SendPort后,再发送图片数据。
    4. 子Isolate处理完,把结果发回主Isolate,主Isolate更新UI。
  • 区分消息类型:在主Isolate的监听回调里,分别处理子Isolate发来的SendPort和图片结果,避免错误完成Completer。
  • 避免过早关闭端口:只有收到最终结果后,才关闭主Isolate的ReceivePort。

内容的提问来源于stack exchange,提问作者Nickolas de Luca Alberton

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 20:30:54