如何在Flutter中使用Model类在ListView中展示嵌套API数据
问题:如何在Flutter ListView中展示解析后的学科数据
你已经成功获取并解析了JSON数据,能打印指定学科名称,接下来我们一步步实现把这些数据展示在ListView里。
先回顾你已有的内容
1. JSON响应
[ { "success": 1, "subject": [ { "subject_id": "5e32874c714fa", "subject_name": "Account", "image": "upload/subject/Account.png", "active": "1", "standard_id": "5d1594e283e1a", "medium_id": "5d15938aa1344" }, { "subject_id": "5da9ff659fb7c", "subject_name": "Biology", "image": "upload/subject/03_logo-1164x484.png", "active": "1", "standard_id": "5d1594e283e1a", "medium_id": "5d15938aa1344" }, { "subject_id": "5da9ff990b1c6", "subject_name": "Chemisty", "image": "upload/subject/02_logo-1168x490.png", "active": "1", "standard_id": "5d1594e283e1a", "medium_id": "5d15938aa1344" }, { "subject_id": "5de76afbd064e", "subject_name": "Computer", "image": "upload/subject/07_logo-1169x486.png", "active": "1", "standard_id": "5d1594e283e1a", "medium_id": "5d15938aa1344" }, { "subject_id": "5d788906c431b", "subject_name": "Devsatya Paperset March 2020", "image": "upload/subject/04_logo-1174x491.png", "active": "1", "standard_id": "5d1594e283e1a", "medium_id": "5d15938aa1344" } ] } ]
2. 已定义的Model类
// To parse this JSON data, do // // final subjectByUser = subjectByUserFromJson(jsonString); import 'dart:convert'; List<SubjectByUser> subjectByUserFromJson(String str) => List<SubjectByUser>.from( json.decode(str).map((x) => SubjectByUser.fromJson(x))); String subjectByUserToJson(List<SubjectByUser> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson()))); class SubjectByUser { SubjectByUser({ required this.success, required this.subject, }); int success; List<Subject> subject; factory SubjectByUser.fromJson(Map<String, dynamic> json) => SubjectByUser( success: json["success"], subject: List<Subject>.from(json["subject"].map((x) => Subject.fromJson(x))), ); Map<String, dynamic> toJson() => { "success": success, "subject": List<dynamic>.from(subject.map((x) => x.toJson())), }; } class Subject { Subject({ required this.subjectId, required this.subjectName, required this.image, required this.active, required this.standardId, required this.mediumId, }); String subjectId; String subjectName; String image; String active; String standardId; String mediumId; factory Subject.fromJson(Map<String, dynamic> json) => Subject( subjectId: json["subject_id"], subjectName: json["subject_name"], image: json["image"], active: json["active"], standardId: json["standard_id"], mediumId: json["medium_id"], ); Map<String, dynamic> toJson() => { "subject_id": subjectId, "subject_name": subjectName, "image": image, "active": active, "standard_id": standardId, "medium_id": mediumId, }; }
3. 当前请求代码
Future getUserSubject(List subject) async { final subjectUrl = "$baseUrl/subject/get_by_user_plan?user_id=609cab2cd5b6c&order_id=1620889722609cd07a601af469889697609cab2cd5b6c&standard_id=5d1594e283e1a&medium_id=5d15938aa1344"; final response = await http.get(Uri.parse(subjectUrl)); final subjects = response.body; final decodedData = jsonDecode(subjects); SubjectByUserModel subjectByUserModel = SubjectByUserModel.fromJson(decodedData); print(subjectByUserModel.subject?[2].subjectName); }
解决方案:实现ListView展示数据
第一步:修正请求方法,返回学科列表
首先,你的请求方法需要返回解析后的学科数据,并且要注意JSON是数组格式,需要取第一个元素解析:
import 'package:http/http.dart' as http; import 'dart:convert'; // 导入你的Model类 import 'path/to/your/subject_model.dart'; Future<List<Subject>?> getUserSubject() async { final subjectUrl = "$baseUrl/subject/get_by_user_plan?user_id=609cab2cd5b6c&order_id=1620889722609cd07a601af469889697609cab2cd5b6c&standard_id=5d1594e283e1a&medium_id=5d15938aa1344"; try { final response = await http.get(Uri.parse(subjectUrl)); if (response.statusCode == 200) { final decodedData = jsonDecode(response.body); // JSON是数组,取第一个元素解析成SubjectByUser SubjectByUser subjectByUser = SubjectByUser.fromJson(decodedData[0]); return subjectByUser.subject; } else { print("请求失败,状态码:${response.statusCode}"); return null; } } catch (e) { print("请求出错:$e"); return null; } }
第二步:在视图层用FutureBuilder构建ListView
在你的页面State类中,使用FutureBuilder来异步获取数据并渲染列表:
import 'package:flutter/material.dart'; // 导入请求方法和Model类 import 'path/to/your/api_service.dart'; import 'path/to/your/subject_model.dart'; class SubjectListPage extends StatefulWidget { const SubjectListPage({super.key}); @override State<SubjectListPage> createState() => _SubjectListPageState(); } class _SubjectListPageState extends State<SubjectListPage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("我的学科"), ), body: FutureBuilder<List<Subject>?>( future: getUserSubject(), builder: (context, snapshot) { // 处理加载中状态 if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } // 处理错误状态 else if (snapshot.hasError) { return Center(child: Text("加载失败:${snapshot.error}")); } // 处理无数据状态 else if (!snapshot.hasData || snapshot.data!.isEmpty) { return const Center(child: Text("暂无学科数据")); } // 数据加载成功,构建ListView else { final subjects = snapshot.data!; return ListView.builder( padding: const EdgeInsets.all(8), itemCount: subjects.length, itemBuilder: (context, index) { final subject = subjects[index]; return Card( margin: const EdgeInsets.symmetric(vertical: 4), child: ListTile( leading: Image.network( // 拼接完整的图片URL,因为返回的是相对路径 "$baseUrl/${subject.image}", width: 50, height: 50, fit: BoxFit.cover, // 图片加载失败时显示默认图标 errorBuilder: (context, error, stackTrace) { return const Icon(Icons.book, size: 50); }, ), title: Text(subject.subjectName), subtitle: Text("学科ID:${subject.subjectId}"), // 可以添加点击事件 onTap: () { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("点击了${subject.subjectName}")), ); }, ), ); }, ); } }, ), ); } }
关键注意事项
- 图片URL拼接:返回的
image字段是相对路径,必须和你的baseUrl拼接才能正确加载图片,比如"$baseUrl/${subject.image}" - 异常处理:添加了try-catch和状态码判断,避免请求出错导致崩溃
- 状态处理:覆盖了加载中、错误、无数据三种状态,提升用户体验
- JSON解析修正:你的原始JSON是数组格式,所以要取
decodedData[0]来解析成SubjectByUser对象
内容的提问来源于stack exchange,提问作者Dhaval Chaudhari
相关产品推荐
相关产品推荐

