Flutter跨Isolate执行Widget截图触发Assertion失败问题求助
在Isolate中执行Widget截图时的断言错误解决方法
我需要在独立的Isolate中对Widget进行截图操作,主线程执行截图功能一切正常,但用compute开启新Isolate执行时触发了如下断言错误:
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: 'dart:ui/window.dart': Failed assertion: line 298 pos 12: '<optimized out>': is not true. E/flutter (20904): #0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:51:61) E/flutter (20904): #1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:40:5) E/flutter (20904): #2 FlutterWindow.viewConfiguration (dart:ui/window.dart:298:12) E/flutter (20904): #3 FlutterView.physicalSize (dart:ui/window.dart:136:28) E/flutter (20904): #4 ScreenshotController.captureFromWidget (package:screenshot/screenshot.dart:123:34) E/flutter (20904): #5 capture (package:multithreading/components/receipt.dart:12:44) E/flutter (20904): #6 _IsolateConfiguration.applyAndTime.<anonymous closure> (package:flutter/src/foundation/_isolates_io.dart:108:21) E/flutter (20904): #7 Timeline.timeSync (dart:developer/timeline.dart:160:22) E/flutter (20904): #8 _IsolateConfiguration.applyAndTime (package:flutter/src/foundation/_isolates_io.dart:106:21) E/flutter (20904): #9 _spawn (package:flutter/src/foundation/_isolates_io.dart:127:67) E/flutter (20904): #10 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:300:17) E/flutter (20904): #11 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)
相关代码
receipt.dart
import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:screenshot/screenshot.dart'; final screenshotController = ScreenshotController(); Future<Uint8List> capture(double pixel) async{ final bytes = await screenshotController.captureFromWidget( Padding( padding: const EdgeInsets.all(12.0), child: Container( height: 500, width: 300, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20), decoration: ShapeDecoration( color: CupertinoColors.systemGreen, shadows: [ BoxShadow( color: Colors.grey.withOpacity(0.5), blurRadius: 6, ), ], ), ), ), delay: Duration.zero, pixelRatio: pixel, ); return bytes; }
computePage.dart
import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'components/receipt.dart'; class ComputePage extends StatefulWidget { const ComputePage({Key? key}) : super(key: key); @override State<ComputePage> createState() => _ComputePageState(); } class _ComputePageState extends State<ComputePage> { Uint8List? widgetImage; Future captureWidget() async { if (widgetImage == null) { widgetImage = await compute(capture, 10.0); // widgetImage = await capture(10.0); // 取消注释此代码可正常运行 } else { widgetImage = null; } setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( height: 500, width: 300, alignment: Alignment.center, decoration: BoxDecoration( color: widgetImage == null ? const Color(0xFF2AA65C) : Colors.white, borderRadius: BorderRadius.circular(30.0), border: Border.all(color: Colors.red, width: 6), ), child: widgetImage == null ? const Text( 'Image', style: TextStyle( color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold, ), ) : Image.memory(widgetImage!), ), const SizedBox(height: 50), ElevatedButton( onPressed: () { captureWidget(); }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFEAF6EF), fixedSize: const Size(double.infinity, 50), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.0), ), ), child: const Text( 'Capture', style: TextStyle( color: Color(0xFF2AA65C), fontSize: 16, fontWeight: FontWeight.w700, ), ), ), ], ), ), ); } }
问题原因
Flutter的UI相关API(包括screenshot包的captureFromWidget)只能在**主线程(UI Isolate)**中调用。后台Isolate是独立的执行环境,没有关联的Flutter UI上下文,无法访问FlutterWindow、FlutterView等核心UI资源,这就是断言失败的根本原因。
解决建议
放弃在Isolate中执行截图:截图操作本质依赖UI上下文,无法在后台Isolate完成。若担心主线程卡顿,可优化截图逻辑:
- 降低
pixelRatio(比如从10.0调整到2.0或3.0,过高的像素比会大幅增加计算负载) - 提前缓存要截图的Widget实例,避免重复构建
- 利用
SchedulerBinding.instance.addPostFrameCallback在UI帧绘制完成后执行截图,减少卡顿感知
- 降低
优化主线程执行方式:修改
captureWidget方法,在主线程空闲时执行截图:import 'package:flutter/scheduler.dart'; Future captureWidget() async { if (widgetImage == null) { await SchedulerBinding.instance.addPostFrameCallback((_) async { widgetImage = await capture(3.0); // 降低像素比减少负载 setState(() {}); }); } else { widgetImage = null; setState(() {}); } }原生截图替代(可选):如果仅需截取当前屏幕上已渲染的Widget,可使用平台原生截图能力,避免通过
captureFromWidget重新构建Widget。
内容的提问来源于stack exchange,提问作者Sardonic777
相关产品推荐
相关产品推荐

