Flutter空安全下解析JSON生成可编辑数据表遇List构造器不可用错误
问题修复与功能实现方案
1 报错原因与data.dart修复
你遇到的构造器报错是Dart 2.12+空安全版本后,官方移除了默认的List()构造器导致的。同时原有代码还存在两处逻辑问题:
List<Results>初始化写法错误,参数传递无效- 实体类字段和你提供的JSON结构不匹配,JSON根节点下是
skills数组,不存在previous/next/results字段
修复后的完整data.dart代码:
class Data { late List<Results> skills; Data.fromJson(Map<String, dynamic> json) { skills = []; // 直接用列表字面量初始化空列表,兼容空安全 if (json['skills'] != null) { json['skills'].forEach((v) { skills.add(Results.fromJson(v)); }); } } } class Results { // 从JSON读取的固定字段 String skills = " "; String testLink = ""; // 新增可编辑字段 int months = 0; double selfScore = 0.0; double testScore = 0.0; String comments = ""; Results.fromJson(Map<String, dynamic> json) { skills = json['skills'] ?? ""; testLink = json['test'] ?? ""; } }
2 依赖配置与JSON修正
首先修正你提供的样例JSON语法错误(缺少数组闭合符):
{ "skills": [ { "skills": "C#", "test": "//www.google.com/" }, { "skills": ".Net Core", "test": "//www.google.com/" }, { "skills": "ASP.Net", "test": "//www.google.com/" } ] }
然后需要在pubspec.yaml中声明本地JSON资源路径,否则无法读取文件:
flutter: assets: - lib/data.json
3 DataProvider功能增强
优化原有数据读取逻辑,新增可编辑字段更新方法:
import 'dart:convert'; import 'package:flutter/widgets.dart'; import 'data.dart'; class MyDataProvider extends ChangeNotifier { Data? d; bool isLoading = false; Future getData(BuildContext context) async { isLoading = true; notifyListeners(); var response = await DefaultAssetBundle.of(context) .loadString('lib/data.json'); var mJson = json.decode(response); d = Data.fromJson(mJson); isLoading = false; notifyListeners(); } // 可编辑字段更新方法 void updateField(int index, { int? months, double? selfScore, double? testScore, String? comments, }) { if (d == null || index >= d!.skills.length) return; if (months != null) d!.skills[index].months = months; if (selfScore != null) d!.skills[index].selfScore = selfScore; if (testScore != null) d!.skills[index].testScore = testScore; if (comments != null) d!.skills[index].comments = comments; notifyListeners(); } }
4 可编辑数据表Widget实现
使用官方DataTable组件实现需求,可编辑字段点击后弹出输入框修改:
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'dataprovider.dart'; class SkillTablePage extends StatefulWidget { const SkillTablePage({super.key}); @override State<SkillTablePage> createState() => _SkillTablePageState(); } class _SkillTablePageState extends State<SkillTablePage> { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { Provider.of<MyDataProvider>(context, listen: false).getData(context); }); } // 编辑弹窗逻辑 void showEditDialog(int index, String field, dynamic currentValue) { final controller = TextEditingController(text: currentValue.toString()); showDialog( context: context, builder: (context) => AlertDialog( title: Text('编辑$field'), content: TextField( controller: controller, keyboardType: field == '使用时长(月)' ? TextInputType.number : field.contains('分数') ? const TextInputType.numberWithOptions(decimal: true) : TextInputType.text, ), actions: [ TextButton(onPressed: () => Navigator.pop(context), child: const Text('取消')), TextButton( onPressed: () { final provider = Provider.of<MyDataProvider>(context, listen: false); switch(field) { case '使用时长(月)': provider.updateField(index, months: int.tryParse(controller.text) ?? 0); break; case '自评分数': provider.updateField(index, selfScore: double.tryParse(controller.text) ?? 0.0); break; case '考试分数': provider.updateField(index, testScore: double.tryParse(controller.text) ?? 0.0); break; case '备注': provider.updateField(index, comments: controller.text); break; } Navigator.pop(context); }, child: const Text('确认'), ) ], ) ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('技能数据表')), body: Consumer<MyDataProvider>( builder: (context, provider, child) { if (provider.isLoading) { return const Center(child: CircularProgressIndicator()); } if (provider.d == null) { return const Center(child: Text('暂无数据')); } return SingleChildScrollView( scrollDirection: Axis.horizontal, child: DataTable( columns: const [ DataColumn(label: Text('skills')), DataColumn(label: Text('months')), DataColumn(label: Text('selfscore')), DataColumn(label: Text('testscore')), DataColumn(label: Text('testlink')), DataColumn(label: Text('comments')), ], rows: provider.d!.skills.asMap().entries.map((entry) { int index = entry.key; Results item = entry.value; return DataRow(cells: [ DataCell(Text(item.skills)), DataCell(Text(item.months.toString()), onTap: () => showEditDialog(index, '使用时长(月)', item.months)), DataCell(Text(item.selfScore.toStringAsFixed(1)), onTap: () => showEditDialog(index, '自评分数', item.selfScore)), DataCell(Text(item.testScore.toStringAsFixed(1)), onTap: () => showEditDialog(index, '考试分数', item.testScore)), DataCell(Text(item.testLink)), DataCell(Text(item.comments.isEmpty ? '点击填写' : item.comments), onTap: () => showEditDialog(index, '备注', item.comments)), ]); }).toList(), ), ); }, ), ); } }
最后在项目入口注册Provider即可正常使用该页面。
内容的提问来源于stack exchange,提问作者AafreenKhan
相关产品推荐
相关产品推荐

