Flutter/Dart:如何将JSON数据按格式存入并展示在List Tile中?
解决Flutter中JSON数据在单个ListTile展示及优化存储问题
问题根源
现有实现将每个事件的四个字段拆分为独立字符串存入缓存,导致读取后每个字段对应一个ListTile,丢失了字段与事件的关联关系,同时存储方案效率低下。
1. 重构存储逻辑,保留事件完整结构
将整个事件列表序列化为JSON字符串存储,确保每个事件的字段关联关系不丢失。
修改获取并存储的代码:
onTap: () async { var newMessage = await ReadCache.getString(key: 'cache1'); var response = await http.get( Uri.parse('http://192.168.1.8:8080/HongLeong/MENU_REQUEST.do?_dc=1658076505340&reset_context=1&table_id=25510&id_MenuAction=3&path=%3Cp%20class%3D%22x-window-header-path%22%3ELoss%20Event%3C%2Fp%3E&ViewType=MENU_REQUEST&gui_open_popup=1&id_Window=17&activeWindowId=mw_17&noOrigUserDate=true&LocalDate=20220718&LocalTime=00482500&TimeZone=Asia%2FShanghai&UserDate=0&UserTime=0&server_name=OPRISK_DATACOLLECTOR&key_id_list=&cell_context_id=0&id_Desktop=100252&operation_key=1000184&operation_sub_num=-1&is_json=1&is_popup=0&is_search_window=0&ccsfw_conf_by_user=0&is_batch=0&previousToken=1658069547560&historyToken=1658076505339&historyUrl=1'), headers: {HttpHeaders.cookieHeader: newMessage}, ); LossEventResponseModel lossEventResponseModel = LossEventResponseModel.fromJson(jsonDecode(response.body)); final listNode = lossEventResponseModel.response.genericListAnswer.listNode; List<Map<String, dynamic>> incidentList = [ for (final json in listNode.map((x) => x.toJson())) { 'Code': json['field'][0]['field_value'], 'Description': json['field'][1]['field_value'], 'Organisation Unit': json['field'][46]['field_value'], 'Date Reported': json['field'][18]['field_value'], } ]; // 将整个事件列表序列化为JSON字符串存储 String incidentListJson = jsonEncode(incidentList); await WriteCache.setString(key: 'cache4', value: incidentListJson); Navigator.of(context).push( MaterialPageRoute(builder: (context) => LossEvent())); }
2. 修改读取与展示逻辑,单个ListTile展示完整事件
读取缓存的JSON字符串并解析为事件列表,每个事件对应一个ListTile,在Tile内组合展示所有字段。
修改读取展示的代码:
body: Column( children: [ Expanded( child: FutureBuilder( future: ReadCache.getString(key: 'cache4'), builder: (context, snapshot) { if (snapshot.hasData && snapshot.data!.isNotEmpty) { // 解析JSON为事件列表 List<Map<String, dynamic>> incidentList = List<Map<String, dynamic>>.from(jsonDecode(snapshot.data!)); return ListView.builder( itemCount: incidentList.length, itemBuilder: (context, index) { final incident = incidentList[index]; return Padding( padding: const EdgeInsets.all(5.0), child: ListTile( tileColor: Colors.blueGrey[200], shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), // Title显示事件编码,Subtitle组合展示其他字段 title: Text( incident['Code'] ?? 'No Code', style: GoogleFonts.poppins( textStyle: const TextStyle( fontWeight: FontWeight.bold, fontSize: 20, ), ), ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Description: ${incident['Description'] ?? 'No Description'}', style: GoogleFonts.poppins(fontSize: 16), ), Text( 'Organisation Unit: ${incident['Organisation Unit'] ?? 'No Unit'}', style: GoogleFonts.poppins(fontSize: 16), ), Text( 'Date Reported: ${incident['Date Reported'] ?? 'No Date'}', style: GoogleFonts.poppins(fontSize: 16), ), ], ), ), ); }); } else { return const Text("No Data"); } }, ), ), ], ),
3. 进阶优化:使用自定义模型类(类型安全)
为避免Map带来的类型不安全问题,创建Incident模型类:
class Incident { final String? code; final String? description; final String? organisationUnit; final String? dateReported; Incident({ this.code, this.description, this.organisationUnit, this.dateReported, }); // 从Map转换为Incident实例 factory Incident.fromMap(Map<String, dynamic> map) { return Incident( code: map['Code'], description: map['Description'], organisationUnit: map['Organisation Unit'], dateReported: map['Date Reported'], ); } // 转换为Map用于序列化 Map<String, dynamic> toMap() { return { 'Code': code, 'Description': description, 'Organisation Unit': organisationUnit, 'Date Reported': dateReported, }; } }
适配模型类的存储与读取逻辑
- 存储时:将
incidentList转换为Incident实例列表再序列化List<Incident> incidents = incidentList.map((map) => Incident.fromMap(map)).toList(); String incidentListJson = jsonEncode(incidents.map((e) => e.toMap()).toList()); await WriteCache.setString(key: 'cache4', value: incidentListJson); - 读取时:解析后转换为
Incident实例列表List<Incident> incidents = List<Map<String, dynamic>>.from(jsonDecode(snapshot.data!)) .map((map) => Incident.fromMap(map)) .toList();
之后即可通过incident.code、incident.description等方式安全访问字段。
内容的提问来源于stack exchange,提问作者JoshuaaMarkk
相关产品推荐
相关产品推荐

