Flutter中FutureBuilder与ListViewBuilder数据加载问题求助
解决Flutter中API返回列表无法获取length的问题
你当前的代码把API返回的结果列表当成了单个ResultModel对象来解析,所以snapshot.data是单个实例,自然没有length属性,也不能用[index]访问元素。以下是具体修复步骤:
1. 调整ResultModel类,添加列表解析方法
在原模型类中新增一个静态方法,用来将API返回的数组解析为ResultModel列表:
class ResultModel { int? examId; String? examName; int? examStream; String? createdAt; String? updatedAt; ResultModel( {this.examId, this.examName, this.examStream, this.createdAt, this.updatedAt}); // 保留原单个对象解析方法 ResultModel.fromJson(Map<String, dynamic> json) { examId = json['exam_id']; examName = json['exam_name']; examStream = json['exam_stream']; createdAt = json['created_at']; updatedAt = json['updated_at']; } // 新增:解析数组为ResultModel列表 static List<ResultModel> fromJsonList(List<dynamic> jsonList) { return jsonList.map((json) => ResultModel.fromJson(json)).toList(); } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['exam_id'] = this.examId; data['exam_name'] = this.examName; data['exam_stream'] = this.examStream; data['created_at'] = this.createdAt; data['updated_at'] = this.updatedAt; return data; } }
2. 修改getResults方法,返回列表类型
将原方法的返回值从单个ResultModel改为List<ResultModel>,适配API返回的数组格式:
Future<List<ResultModel>> getResults() async { SharedPreferences prefs = await SharedPreferences.getInstance(); var token = await prefs.getString('token'); var response = await http.get( Uri.parse('http://localhost:8000/api/student/results'), headers: { 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': "Bearer $token", }, ); // 将响应体解析为数组,再转成ResultModel列表 return ResultModel.fromJsonList(jsonDecode(response.body)); }
3. 更新FutureBuilder和ListView代码
调整FutureBuilder的泛型类型,并用列表长度作为itemCount,正常访问列表元素:
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('My Results')), body: Padding( padding: const EdgeInsets.all(18.0), child: FutureBuilder<List<ResultModel>>( future: getResults(), builder: (context, snapshot) { if (snapshot.hasData) { return ListView.builder( // 使用列表长度作为itemCount itemCount: snapshot.data!.length, itemBuilder: (BuildContext context, int index) { final result = snapshot.data![index]; return ListTile( contentPadding: const EdgeInsets.all(5.0), leading: const Icon( Icons.menu_book, color: Colors.blueAccent, ), // 正常访问模型属性 title: Text(result.examId.toString()), subtitle: Text(result.examName ?? '无考试名称'), trailing: const Icon(Icons.visibility), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => DetailResult())); }, ); }, ); } else if (snapshot.hasError) { // 新增错误提示,方便调试 return Center(child: Text('加载失败: ${snapshot.error}')); } else { return const Center(child: CircularProgressIndicator()); } }, ), ), ); }
额外优化建议
可以在initState中提前加载数据并存入状态变量,避免每次build都重复请求API:
List<ResultModel>? _results; @override void initState() { super.initState(); _loadResults(); } Future<void> _loadResults() async { final data = await getResults(); setState(() { _results = data; }); } // 后续FutureBuilder的future改为Future.value(_results),或直接判断_results状态
内容的提问来源于stack exchange,提问作者swapnil mane
相关产品推荐
相关产品推荐

