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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 08:48:31