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

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资源,这就是断言失败的根本原因。

解决建议

  1. 放弃在Isolate中执行截图:截图操作本质依赖UI上下文,无法在后台Isolate完成。若担心主线程卡顿,可优化截图逻辑:

    • 降低pixelRatio(比如从10.0调整到2.0或3.0,过高的像素比会大幅增加计算负载)
    • 提前缓存要截图的Widget实例,避免重复构建
    • 利用SchedulerBinding.instance.addPostFrameCallback在UI帧绘制完成后执行截图,减少卡顿感知
  2. 优化主线程执行方式:修改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(() {});
      }
    }
    
  3. 原生截图替代(可选):如果仅需截取当前屏幕上已渲染的Widget,可使用平台原生截图能力,避免通过captureFromWidget重新构建Widget。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 18:45:28