You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,
                ),
              );
            },
          );
        },
      ),
    );
  }
}

关键修复点

  1. 避免重复请求:将API请求赋值给State变量_quizFuture,在initState中初始化,防止每次build都发起新请求
  2. 空安全处理:对Quizzes数组做空判断,用?? []兜底,确保不会出现空指针
  3. 取消索引复用:不再用外层ListView的index访问Quizzes数组,改为直接遍历数组元素,支持单课程多Quiz的场景
  4. 空数据适配:当Quizzes为空时,ExpansionTile的子项设为空列表,符合需求

内容的提问来源于stack exchange,提问作者Tahir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 12:55:18