如何确保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
相关产品推荐
相关产品推荐

