Flutter中ListView.builder加载JSON数据出现RangeError(index)问题求助
问题修复方案
错误根源
你遇到的RangeError是因为在ExpansionTile的子项中,错误复用了外层ListView的index去访问Quizzes数组——比如第二个课程(index=1)的Quizzes是空数组,此时Quizzes[index]即Quizzes[1]必然触发数组越界。同时你没有判断Quizzes数组是否为空,直接访问内部元素。
步骤1:优化API请求代码
替换原全局变量+无返回值的API方法,改为带类型返回、异常处理的实现:
Future<Map<String, dynamic>> quizListingApi() async { try { final response = await http.get(Uri.parse('json url')); if (response.statusCode == 200) { return jsonDecode(response.body); } else { throw Exception('请求失败:${response.statusCode}'); } } catch (e) { throw Exception('网络错误:$e'); } }
步骤2:修复Build方法逻辑
修改Widget的State类,解决数组越界问题,同时支持空数据场景:
class _YourQuizPageState extends State<YourQuizPage> { late Future<Map<String, dynamic>> _quizFuture; @override void initState() { super.initState(); _quizFuture = quizListingApi(); // 初始化时发起请求,避免重复调用 } @override Widget build(BuildContext context) { return Scaffold( body: FutureBuilder<Map<String, dynamic>>( future: _quizFuture, builder: (context, AsyncSnapshot<Map<String, dynamic>> snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: Text('Loading')); } else if (snapshot.hasError) { return Center(child: Text('错误:${snapshot.error}')); } else if (!snapshot.hasData || snapshot.data!['QuizzesData'] == null) { return const Center(child: Text('无数据')); } final quizzesData = snapshot.data!['QuizzesData'] as List; return ListView.builder( itemCount: quizzesData.length, itemBuilder: (context, index) { final course = quizzesData[index]; final courseTitle = course['CourseTitle'] ?? '无课程名称'; final quizzes = course['Quizzes'] as List? ?? []; // 构建子项:空数组时返回空列表,否则遍历每个Quiz List<Widget> tileChildren = []; if (quizzes.isNotEmpty) { for (var quiz in quizzes) { tileChildren.addAll([ Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('标题:${quiz['Title'] ?? '无标题'}'), Text('截止日期:${quiz['EndDate'] ?? '无截止日期'}'), Text('状态:${quiz['QuizStatus'] ?? '无状态'}'), const Divider(), ], ), ), ]); } } return Card( child: ExpansionTile( title: Text(courseTitle), children: tileChildren, ), ); }, ); }, ), ); } }
关键修复点
- 避免重复请求:将API请求赋值给State变量
_quizFuture,在initState中初始化,防止每次build都发起新请求 - 空安全处理:对
Quizzes数组做空判断,用?? []兜底,确保不会出现空指针 - 取消索引复用:不再用外层ListView的
index访问Quizzes数组,改为直接遍历数组元素,支持单课程多Quiz的场景 - 空数据适配:当
Quizzes为空时,ExpansionTile的子项设为空列表,符合需求
内容的提问来源于stack exchange,提问作者Tahir
相关产品推荐
相关产品推荐

