Flutter Isolate旋转图片报错:非法参数无法发送对象
问题原因及解决方案
异常根源
你遇到的Invalid argument(s): Illegal argument in isolate message异常,核心是Isolate间消息传递的逻辑完全混乱,导致不可序列化的_AsyncCompleter对象被卷入消息传递流程。具体问题如下:
主Isolate没给子Isolate发图片数据
子Isolate启动后一直在等图片的Uint8List,但你的rotateImage函数里,主Isolate只启动了子Isolate,从来没把foto(图片字节)传过去,子Isolate根本没机会执行旋转逻辑。错误把SendPort当成结果给了Completer
子Isolate启动后会先把自己的ReceivePort.sendPort发回主Isolate,主Isolate的receivePort.listen第一次收到的就是这个SendPort。你直接用这个SendPort完成了Completer,而Completer原本要接收的是Uint8List。这种错误的类型匹配,加上Completer内部的异步状态对象不可跨Isolate传递,直接触发了异常。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通信流程:
- 主Isolate启动子Isolate时,传自己的SendPort。
- 子Isolate先把自己的SendPort发回主Isolate,建立双向通信通道。
- 主Isolate拿到子Isolate的SendPort后,再发送图片数据。
- 子Isolate处理完,把结果发回主Isolate,主Isolate更新UI。
- 区分消息类型:在主Isolate的监听回调里,分别处理子Isolate发来的SendPort和图片结果,避免错误完成Completer。
- 避免过早关闭端口:只有收到最终结果后,才关闭主Isolate的ReceivePort。
内容的提问来源于stack exchange,提问作者Nickolas de Luca Alberton
相关产品推荐
相关产品推荐

