Flutter点击支付调用PaymentViewModel报Null类型不匹配错误
Flutter支付功能调用ViewModel空类型报错修复
错误根因
报错核心原因是你在_PayfastPaymentState中声明了late PaymentViewModel model;,但从未对model变量做实例化初始化:late关键字的作用是向Dart编译器承诺“该变量会在使用前完成非空赋值”,但实际代码里你没有给model赋值任何PaymentViewModel实例,点击按钮调用model.payment()时拿到的是null,和声明的非空PaymentViewModel类型不匹配,直接抛出类型转换错误。
除此之外代码里还存在几个会引发后续异常的隐藏问题:
- PaymentViewModel内部重复定义了和页面同名的文本编辑控制器,payment方法读取的是ViewModel内部空controller的文本值,根本拿不到用户在页面输入框填写的金额、商品名
- PaymentViewModel中声明的
late API api同样没有初始化,就算model实例化完成,调用支付接口时也会触发空错误 - payment方法内的错误判断逻辑完全无效:方法开头手动将
paymentErrorMessage赋值为null,后续的非空判断永远不会执行 - 页面内的文本编辑控制器没有在组件销毁时释放,会造成内存泄漏
修正后代码
1. 支付表单页修正
class PayfastPayment extends StatefulWidget { PayfastPayment({Key? key}) : super(key: key); @override _PayfastPaymentState createState() => _PayfastPaymentState(); } class _PayfastPaymentState extends State<PayfastPayment> { TextEditingController amountController = TextEditingController(); TextEditingController itemNameController = TextEditingController(); // 直接初始化ViewModel实例 final PaymentViewModel model = PaymentViewModel(); var client = http.Client(); @override void dispose() { // 释放控制器避免内存泄漏 amountController.dispose(); itemNameController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(centerTitle: true, title: const Text("Payment Page")), body: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ TextFormField( controller: amountController, decoration: const InputDecoration( border: UnderlineInputBorder(), labelText: 'Amount', ), ), const SizedBox( height: 100, ), TextFormField( controller: itemNameController, decoration: const InputDecoration( border: UnderlineInputBorder(), labelText: 'Item Name', ), ), SizedBox( width: 220, height: 100, child: InkWell( onTap: () { // 增加输入空值判断 final amount = amountController.text.trim(); final itemName = itemNameController.text.trim(); if(amount.isEmpty || itemName.isEmpty){ ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("请输入金额和商品名称")) ); return; } print("Amount: $amount Item: $itemName"); model.payment(amount, itemName); }, child: Container( alignment: Alignment.center, color: Colors.blue, child: const Center( child: Text("Pay", style: TextStyle(fontSize: 22, color: Colors.white))), ), ), ), ], ), ); } }
2. PaymentViewModel视图模型修正
class PaymentViewModel { // 移除重复的文本控制器,直接使用页面传入的参数 // 初始化API实例,替换为你自己项目中的API初始化逻辑 final API api = API(); String? errorMessage; // 给payFast设置初始值避免late初始化错误 String payFast = ""; void payment(String amount, String itemName) { // 移除无效的固定null判断,可在此处补充自定义参数校验逻辑 if(amount.isEmpty || itemName.isEmpty){ errorMessage = "支付参数不完整"; return; } api .payFastPayment(amount: amount, item_name: itemName) .then((createdPayment) { if (createdPayment == null) { errorMessage = "Something went wrong. Please try again."; } else { payFast = createdPayment; } print("It reaches here"); }).catchError((error) { errorMessage = '${error.toString()}'; }); } }
额外说明
如果你的项目使用了状态管理框架(比如Provider、GetX、Riverpod),需要按照对应框架的规则初始化/获取ViewModel实例,不要直接在State里硬编码创建实例,否则会出现状态不共享的问题。
内容的提问来源于stack exchange,提问作者SaDev
相关产品推荐
相关产品推荐

