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

如何确保return语句在build回调执行完成后才执行?

Dart PDF代码调度问题修复

问题场景

这段代码尝试创建PDF页面标识,但运行时会报错——延迟声明的变量w还没被赋值就被访问,因为pw.Page的build回调是在return w之后才执行的。

原代码:

import 'package:pdf/widgets.dart' as pw;

class PdfPageIdentification {
  PackageInfo packageInfo;
  String smartboxId;
  String smartboxMacAddress;
  pw.Widget? label;
  pw.Page? page;

  PdfPageIdentification(
      {required this.packageInfo,
      required this.smartboxId,
      required this.smartboxMacAddress,
      this.label,
      this.page});
}

/// Creates the battery identification label as a PDF file
static Future<PdfPageIdentification> identificationSheetPage(
    PeripheralManufacturerData data) async {
  final packageInfo = await PackageInfo.fromPlatform();

  late PdfPageIdentification w;
  final page = pw.Page(
      pageFormat: PdfPageFormat.a4,
      margin: pw.EdgeInsets.symmetric(horizontal: 180),
      // margin: pw.EdgeInsets.all(40),
      build: (pw.Context context) {
        w = identificationSheet(data, packageInfo, context);

        return w.label!;
      });

  w.page = page;
  return w;
}

问题原因

pw.Page的build回调是延迟执行的,只有当PDF框架需要渲染页面内容时才会触发。而代码里在创建page后立刻就去给w.page赋值并返回w,这时候build还没执行,w根本没被初始化,自然会抛出未赋值的错误。

修复方案

调整执行顺序:先创建PdfPageIdentification实例,再基于它的label创建pw.Page,最后把page关联回实例。这样所有操作都是同步顺序执行,不会依赖延迟的回调。

基础修复版本(无需依赖pw.Context生成label)

import 'package:pdf/widgets.dart' as pw;

class PdfPageIdentification {
  PackageInfo packageInfo;
  String smartboxId;
  String smartboxMacAddress;
  pw.Widget? label;
  pw.Page? page;

  PdfPageIdentification(
      {required this.packageInfo,
      required this.smartboxId,
      required this.smartboxMacAddress,
      this.label,
      this.page});
}

/// Creates the battery identification label as a PDF file
static Future<PdfPageIdentification> identificationSheetPage(
    PeripheralManufacturerData data) async {
  final packageInfo = await PackageInfo.fromPlatform();
  // 先通过identificationSheet创建好实例,拿到label
  final w = identificationSheet(data, packageInfo, null);
  
  // 用已有的label创建page
  final page = pw.Page(
      pageFormat: PdfPageFormat.a4,
      margin: pw.EdgeInsets.symmetric(horizontal: 180),
      build: (pw.Context context) {
        return w.label!;
      });
  
  // 最后把page赋值给w并返回
  w.page = page;
  return w;
}

适配需pw.Context生成label的版本

如果identificationSheet必须依赖pw.Context才能生成正确的label,可以提前初始化w,再在build回调里更新label属性:

static Future<PdfPageIdentification> identificationSheetPage(
    PeripheralManufacturerData data) async {
  final packageInfo = await PackageInfo.fromPlatform();
  // 提前初始化w,填充已知字段
  final w = PdfPageIdentification(
    packageInfo: packageInfo,
    smartboxId: data.smartboxId, // 假设data包含对应字段
    smartboxMacAddress: data.smartboxMacAddress,
  );
  
  final page = pw.Page(
      pageFormat: PdfPageFormat.a4,
      margin: pw.EdgeInsets.symmetric(horizontal: 180),
      build: (pw.Context context) {
        // 用context生成label并赋值给w
        final generatedLabel = identificationSheetGetLabel(data, packageInfo, context);
        w.label = generatedLabel;
        return generatedLabel;
      });
  
  w.page = page;
  return w;
}

内容的提问来源于stack exchange,提问作者Stéphane de Luca

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 22:10:31