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

Flutter调用HTTP API在PageView.builder展示数据报错求助

问题分析与修复方案

错误根源

  1. 数据结构访问错误:你尝试通过data[index]['data']['name']访问数据,但API返回结构并非嵌套data字段,导致data[index]['data']为null,触发[]调用null的异常。
  2. 未处理请求失败场景:HTTP请求失败时,data保持初始null值,后续调用data.length或访问元素直接报错。
  3. FutureBuilder使用不当:每次build都会重复调用getData()发起请求,且未正确处理加载/错误状态。
  4. 分页指示器数据源失效:使用空数组postList生成指示器,导致没有分页点显示。

修复步骤

1. 修正数据获取逻辑

初始化data为空数组,添加异常捕获和错误处理,避免null状态:

List<dynamic> data = []; // 初始化为空数组,而非null

Future<void> getData() async {
  try {
    final response = await http.get(Uri.parse('https://berequirement.herokuapp.com/products'));

    if (response.statusCode == 200) {
      // API直接返回产品数组,无需嵌套data字段
      data = jsonDecode(response.body);
      setState(() {}); // 更新UI
    } else {
      print('请求失败,状态码:${response.statusCode}');
    }
  } catch (e) {
    print('网络请求错误:$e');
  }
}

2. 优化FutureBuilder使用

在initState中发起请求,避免重复调用,直接通过data的空状态判断加载状态:

@override
void initState() {
  _controller = PageController(initialPage: 0);
  getData(); // 初始化时仅发起一次请求
  super.initState();
}

// 替换原FutureBuilder逻辑
child: data.isEmpty
    ? const Center(child: Text('Loading ...'))
    : PageView.builder(
        controller: _controller,
        itemCount: data.length,
        onPageChanged: (int index) {
          setState(() {
            currentIndex = index;
          });
        },
        itemBuilder: (context, index) {
          final product = data[index];
          return Padding(
            padding: const EdgeInsets.all(40),
            child: Column(
              children: [
                Text(
                  product['name'], // 直接访问字段,移除无效的['data']层级
                  style: GoogleFonts.poppins(
                    fontWeight: FontWeight.bold,
                    fontSize: 22,
                  ),
                ),
                const SizedBox(height: 20),
                Text(
                  product['code'],
                  textAlign: TextAlign.center,
                  style: GoogleFonts.poppins(
                      fontWeight: FontWeight.bold,
                      fontSize: 14,
                      color: Colors.grey),
                )
              ],
            ),
          );
        },
      ),

3. 修复分页指示器

将指示器数据源改为data.length,确保分页点正常显示:

Row(
  mainAxisAlignment: MainAxisAlignment.center,
  children: List.generate(
    data.length, // 用产品数组长度生成指示器
    (index) => buildDot(index, context),
  ),
)

4. 补充缺失的buildDot方法

如果未实现分页点样式,添加以下代码:

Widget buildDot(int index, BuildContext context) {
  return Container(
    width: currentIndex == index ? 12 : 8,
    height: 8,
    margin: const EdgeInsets.symmetric(horizontal: 4),
    decoration: BoxDecoration(
      borderRadius: BorderRadius.circular(4),
      color: currentIndex == index ? Colors.blue : Colors.grey.shade300,
    ),
  );
}

完整修正代码

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int currentIndex = 0;
  late PageController _controller;
  List<dynamic> data = [];

  @override
  void initState() {
    _controller = PageController(initialPage: 0);
    getData();
    super.initState();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  Future<void> getData() async {
    try {
      final response = await http.get(Uri.parse('https://berequirement.herokuapp.com/products'));

      if (response.statusCode == 200) {
        data = jsonDecode(response.body);
        setState(() {});
      } else {
        print('请求失败,状态码:${response.statusCode}');
      }
    } catch (e) {
      print('网络请求错误:$e');
    }
  }

  Widget buildDot(int index, BuildContext context) {
    return Container(
      width: currentIndex == index ? 12 : 8,
      height: 8,
      margin: const EdgeInsets.symmetric(horizontal: 4),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(4),
        color: currentIndex == index ? Colors.blue : Colors.grey.shade300,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Expanded(
            child: Container(
              height: 500,
              width: 300,
              child: data.isEmpty
                  ? const Center(child: Text('Loading ...'))
                  : PageView.builder(
                      controller: _controller,
                      itemCount: data.length,
                      onPageChanged: (int index) {
                        setState(() {
                          currentIndex = index;
                        });
                      },
                      itemBuilder: (context, index) {
                        final product = data[index];
                        return Padding(
                          padding: const EdgeInsets.all(40),
                          child: Column(
                            children: [
                              Text(
                                product['name'],
                                style: GoogleFonts.poppins(
                                  fontWeight: FontWeight.bold,
                                  fontSize: 22,
                                ),
                              ),
                              const SizedBox(height: 20),
                              Text(
                                product['code'],
                                textAlign: TextAlign.center,
                                style: GoogleFonts.poppins(
                                    fontWeight: FontWeight.bold,
                                    fontSize: 14,
                                    color: Colors.grey),
                              )
                            ],
                          ),
                        );
                      },
                    ),
            ),
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: List.generate(
              data.length,
              (index) => buildDot(index, context),
            ),
          ),
        ],
      ),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 15:31:02