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

Flutter Null Safety:如何处理含Null值的外部API数据?

解决Flutter空安全下API返回Null值的问题

针对你遇到的"Null check operator used on a null value"错误,核心是避免强制非空断言(!)直接作用于可能为null的值,同时在模型类、Widget渲染、数据请求环节做完整的空值处理,以下是具体修改方案:

1. 模型类(AgentContract)适配空安全

将API可能返回Null的字段标记为可空类型(?),并在fromJson方法中为必填字段设置兜底默认值,确保实例化时不会出现非空字段为null的情况:

class AgentContract {
  // 允许API返回Null的字段标记为可空
  final String? contractName;
  final int? contractId;
  final String? agentName;
  // 必须有值的字段,用默认值兜底
  final String contractStatus;

  AgentContract({
    this.contractName,
    this.contractId,
    this.agentName,
    required this.contractStatus,
  });

  factory AgentContract.fromJson(Map<String, dynamic> json) {
    return AgentContract(
      contractName: json['contract_name'] as String?,
      contractId: json['contract_id'] as int?,
      agentName: json['agent_name'] as String?,
      // 若API返回Null,用默认值替代
      contractStatus: json['contract_status'] as String? ?? '未生效',
    );
  }
}

2. AgentContractItem:安全渲染可空字段

移除!断言,改用??提供默认文本,或通过条件判断处理空值,确保渲染时不会触发空安全错误:

class AgentContractItem extends StatelessWidget {
  final AgentContract contract;

  const AgentContractItem({super.key, required this.contract});

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // 空值时显示默认文本
            Text(
              contract.contractName ?? '未命名合同',
              style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 8),
            // 数字类型空值转字符串默认值
            Text('合同ID:${contract.contractId ?? '无'}'),
            const SizedBox(height: 8),
            Text('经办人:${contract.agentName ?? '未指定'}'),
            const SizedBox(height: 8),
            Text('状态:${contract.contractStatus}'),
          ],
        ),
      ),
    );
  }
}

3. AgentTabScreen:安全处理API返回的列表数据

确保API返回的列表本身不为null,同时处理加载状态和空列表场景:

class AgentTabScreen extends StatefulWidget {
  const AgentTabScreen({super.key});

  @override
  State<AgentTabScreen> createState() => _AgentTabScreenState();
}

class _AgentTabScreenState extends State<AgentTabScreen> {
  List<AgentContract> _contracts = [];
  bool _isLoading = true;

  @override
  void initState() {
    super.initState();
    _fetchContracts();
  }

  Future<void> _fetchContracts() async {
    try {
      final response = await http.get(Uri.parse('你的API地址'));
      final dynamic responseData = json.decode(response.body);
      
      setState(() {
        // 若API返回非List类型,直接赋值为空列表
        _contracts = (responseData as List?)
                ?.map((item) => AgentContract.fromJson(item as Map<String, dynamic>))
                .toList() ?? [];
        _isLoading = false;
      });
    } catch (e) {
      setState(() {
        _contracts = [];
        _isLoading = false;
      });
      // 可添加错误提示逻辑
    }
  }

  @override
  Widget build(BuildContext context) {
    if (_isLoading) {
      return const Center(child: CircularProgressIndicator());
    }

    if (_contracts.isEmpty) {
      return const Center(child: Text('暂无合同数据'));
    }

    return ListView.builder(
      padding: const EdgeInsets.symmetric(vertical: 8),
      itemCount: _contracts.length,
      itemBuilder: (context, index) => AgentContractItem(contract: _contracts[index]),
    );
  }
}

通用空安全技巧

  • 杜绝随意使用!:只有当你能100%确认值不为null时,才使用强制非空断言
  • 嵌套空值处理:对于深层嵌套的可空字段,用?.链式调用+??兜底,比如contract?.agent?.phone ?? '无联系方式'
  • 类型安全转换:在fromJson中尽量使用as?类型转换,避免类型转换错误导致的空值问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 15:05:12