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

如何解决Dart 3.0.5中SQLite保存数据时的空检查运算符异常

问题

我已将现有项目迁移至Dart 3.0.5,起初通过添加?和!解决了空安全问题,应用可正常运行。但现在在SQLite中保存数据时,会抛出运行时错误Null check operator used on a null value,尝试使用??运算符也报错,相关核心代码如下:

Future _onSubmit() async {
  try {
    int _result = 0;
    if (_formKey.currentState!.validate()) {
      if (_isSupplier == false && _isCustomer == false) {
        showToast(global.appLocaleValues!['vel_select_ac_type']);
      } else {
        setState(() {});
        if (_isCustomer == true && _isSupplier == false) {
          _accountType = 'Customer';
        } else if (_isCustomer == false && _isSupplier == true) {
          _accountType = 'Supplier';
        } else if (_isCustomer == true && _isSupplier == true) {
          _accountType = ',Customer,Supplier,';
        }
        account!.accountType = _accountType!;
        account!.firstName = _cFirstName.text.trim();
        account!.lastName = _cLastName.text.trim();
        account!.middleName = _cMiddleName.text.trim();
        account!.mobile = _cMobile.text.trim();

        account!.phone = _cPhone.text.trim();
        account!.email = _cEmail.text.trim();
        if (_birthDate != null) {
          account!.birthdate = DateTime.parse(_birthDate!);
        }
        if (_anniversary != null) {
          account!.anniversary = DateTime.parse(_anniversary!);
        }
        account!.gender = _gender!;
        account!.imagePath = _photopath!;
        account!.addressLine1 = _cAddressLine1.text.trim();
        account!.addressLine2 = _cAddressLine2.text.trim();
        account!.city = _cCity.text.trim();
        account!.state = _cState.text.trim();
        account!.country = _cCountry.text.trim();
        account!.namePrefix = _cNamePrefix.text.trim();
        account!.nameSuffix = _cNameSuffix.text.trim();
        account!.businessName = _cBusinessName.text.trim();
        account!.gstNo = _cGstNo.text.trim();
        if (_cPincode.text.isNotEmpty) {
          account!.pincode = int.parse(_cPincode.text.trim());
        }
        account!.isActive = _isActive!;
        account!.isDelete = false;
        print('${account!.accountType}');
        print('${account!.accountCode}');
        if (account!.id == null) {
          // add account
          _result = (await dbHelper.accountInsert(account!))!;
          account!.id = _result;
        } else {
          // update account
          _result = (await dbHelper.accountUpdate(account!))!;
          AccountSearch accountSearch = AccountSearch();
          Navigator.of(context).pushReplacement(MaterialPageRoute(
              builder: (BuildContext context) => AccountScreen(
                    redirectToCustomersTab: (isAddAsCustomer) ? true : false,
                    a: widget.analytics,
                    o: widget.observer,
                    accountSearch: accountSearch,
                  )));
        }

        if (_result > 0) {
          int notificationId = int.parse(
              global.moduleIds['Account'].toString() +
                  '01' +
                  account!.id.toString());
          if (account!.birthdate != null &&
              account!.anniversary != null &&
              account!.birthdate!.month == account!.anniversary!.month &&
              account!.birthdate!.day == account!.anniversary!.day &&
              (_oldBirthday != account!.birthdate ||
                  _oldAnniversary != account!.anniversary)) {
            await br.scheduleNotification(
                notificationId,
                br
                    .getNextEventDate(account!.birthdate!)
                    .add(Duration(hours: tod.hour, minutes: tod.minute)),
                '${br.generateAccountName(account!)}\'s Birthday & Anniversary',
                'on ${DateFormat('MMMM dd').format(account!.birthdate!)}',
                '{"module":"Account","id":"${account!.id}"}',
                setNextDate: true);
          } else {
            if (account!.birthdate != null &&
                _oldBirthday != account!.birthdate) {
              int notificationId = int.parse(
                  global.moduleIds['Account'].toString() +
                      '02' +
                      account!.id.toString());
              await br.scheduleNotification(
                  notificationId,
                  br
                      .getNextEventDate(account!.birthdate!)
                      .add(Duration(hours: tod.hour, minutes: tod.minute)),
                  '${br.generateAccountName(account!)}\'s Birthday',
                  'on ${DateFormat('MMMM dd').format(account!.birthdate!)}',
                  '{"module":"Account","id":"${account!.id}"}',
                  setNextDate: true);
            }
            if (account!.anniversary != null &&
                _oldAnniversary != account!.anniversary) {
              int notificationId = int.parse(
                  global.moduleIds['Account'].toString() +
                      '03' +
                      account!.id.toString());
              await br.scheduleNotification(
                  notificationId,
                  br
                      .getNextEventDate(account!.anniversary!)
                      .add(Duration(hours: tod.hour, minutes: tod.minute)),
                  '${br.generateAccountName(account!)}\'s Anniversary',
                  'on ${DateFormat('MMMM dd').format(account!.anniversary!)}',
                  '{"module":"Account","id":"${account!.id}"}',
                  setNextDate: true);
            }
          }
          setState(() {});
          if (returnScreenId == 0) {
            AccountSearch accountSearch = AccountSearch();
            Navigator.of(context).pushReplacement(MaterialPageRoute(
                builder: (BuildContext context) => AccountScreen(
                      a: widget.analytics,
                      o: widget.observer,
                      accountSearch: accountSearch,
                      redirectToCustomersTab:
                          (isAddAsCustomer) ? true : false,
                    )));
          } else if (returnScreenId == 1) {
            Navigator.of(context).pop(account);
          }
        }
      }
    } else {
      _autovalidate = true;
      setState(() {});
    }
  } catch (e) {
    print('Exception - accountAddScreen.dart - _onSubmit(): ' + e.toString());
  }
}
解决方案

错误根源是代码中滥用!强制解包null值,以下是针对性修复方案:

  • 确保account实例已初始化:
    如果是新增账号场景,提前实例化Account对象(比如account = Account();),避免account为null时使用account!触发错误。

  • 修复_accountType的空值问题:
    给_accountType设置默认值兜底,避免意外null:

    String _accountType = '';
    // 原有赋值逻辑...
    account!.accountType = _accountType; // 无需再加!
    
  • 处理用户可选字段的null值:
    对于_gender、_photopath、_isActive这类用户可能未设置的字段,用??设置合理默认值,而非强制解包:

    account!.gender = _gender ?? 'Unknown';
    account!.imagePath = _photopath ?? '';
    account!.isActive = _isActive ?? true;
    
  • 安全处理数据库操作返回值:
    数据库插入/更新可能返回null(比如操作失败),先判断再赋值:

    // 新增账号时
    var insertResult = await dbHelper.accountInsert(account!);
    if (insertResult != null) {
      _result = insertResult;
      account!.id = _result;
    } else {
      // 提示用户插入失败
    }
    
    // 更新账号时
    var updateResult = await dbHelper.accountUpdate(account!);
    if (updateResult != null) {
      _result = updateResult;
    } else {
      // 提示用户更新失败
    }
    
  • 修复国际化文本的空值问题:
    用??设置默认提示,避免global.appLocaleValues为null时触发错误:

    showToast(global.appLocaleValues?['vel_select_ac_type'] ?? '请选择账户类型');
    
  • 安全生成notificationId:
    确保global.moduleIds['Account']不为null再转换为字符串:

    String moduleId = global.moduleIds['Account']?.toString() ?? '0';
    int notificationId = int.parse(moduleId + '01' + account!.id.toString());
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 08:52:01