Flutter如何同时返回嵌套JSON中的LocationData与MediaData并在FutureBuilder中使用
嵌套JSON数据同时获取LocationData与MediaData的实现方案
示例JSON结构
{ "location": { "id": 1, "name": "Central Park", "address": "New York, NY" }, "media": [ { "id": 101, "url": "https://example.com/park1.jpg", "type": "image" }, { "id": 102, "url": "https://example.com/park_video.mp4", "type": "video" } ] }
模型代码
保留原有LocationData和MediaData模型,新增CombinedData模型包裹两类数据,并实现[]操作符支持Map式访问:
class LocationData { final int id; final String name; final String address; LocationData({required this.id, required this.name, required this.address}); factory LocationData.fromJson(Map<String, dynamic> json) { return LocationData( id: json['id'], name: json['name'], address: json['address'], ); } } class MediaData { final int id; final String url; final String type; MediaData({required this.id, required this.url, required this.type}); factory MediaData.fromJson(Map<String, dynamic> json) { return MediaData( id: json['id'], url: json['url'], type: json['type'], ); } } class CombinedData { final LocationData location; final List<MediaData> media; CombinedData({required this.location, required this.media}); factory CombinedData.fromJson(Map<String, dynamic> json) { return CombinedData( location: LocationData.fromJson(json['location']), media: (json['media'] as List) .map((item) => MediaData.fromJson(item)) .toList(), ); } // 支持snapshot.data['media']/['location']的访问方式 dynamic operator [](String key) { switch (key) { case 'location': return location; case 'media': return media; default: throw ArgumentError('Invalid key: $key'); } } }
API请求代码
使用http库请求并解析数据为CombinedData:
import 'dart:convert'; import 'package:http/http.dart' as http; Future<CombinedData> fetchCombinedData() async { final response = await http.get(Uri.parse('https://your-api-endpoint.com/data')); if (response.statusCode == 200) { final jsonResponse = jsonDecode(response.body); return CombinedData.fromJson(jsonResponse); } else { throw Exception('Failed to load combined data'); } }
FutureBuilder页面代码
在页面中通过FutureBuilder获取并展示两类数据:
import 'package:flutter/material.dart'; class DataDisplayPage extends StatelessWidget { final Future<CombinedData> combinedDataFuture = fetchCombinedData(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Location & Media')), body: FutureBuilder<CombinedData>( future: combinedDataFuture, builder: (context, snapshot) { if (snapshot.hasData) { return Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 展示Location数据 Text('地点: ${snapshot.data!['location'].name}', style: const TextStyle(fontSize: 18)), Text('地址: ${snapshot.data!['location'].address}', style: const TextStyle(fontSize: 16)), const SizedBox(height: 20), const Text('媒体列表:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), // 遍历展示Media数据 Expanded( child: ListView.builder( itemCount: snapshot.data!['media'].length, itemBuilder: (context, index) { final mediaItem = snapshot.data!['media'][index]; return ListTile( title: Text('类型: ${mediaItem.type}'), subtitle: Text('链接: ${mediaItem.url}'), ); }, ), ), ], ), ); } else if (snapshot.hasError) { return Center(child: Text('加载失败: ${snapshot.error}')); } // 加载状态 return const Center(child: CircularProgressIndicator()); }, ), ); } }
核心说明
- 通过
CombinedData模型统一解析嵌套的JSON结构,避免单独解析的繁琐 - 实现
operator[]让模型支持类似Map的键值访问,满足你要求的snapshot.data['media'][0].fieldname调用方式 - FutureBuilder中直接通过键名访问对应数据集合,再调用模型字段展示内容
内容的提问来源于stack exchange,提问作者jamie1231
相关产品推荐
相关产品推荐

