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

Flutter ListView无法展示API返回响应数据的问题求助

问题排查结论

页面空白和ListView布局没关系,核心是数据链路全程断了:

  • initState里给objectList赋值的代码被你注释了,就算放开也没用,signInData方法定义的返回值是void,根本拿不到解析后的数据
  • 接口返回200之后你直接跳转到无参的ResultsPage,既没解析接口返回的JSON,也没把数据传给结果页,结果页初始化时objectList永远是空数组,itemCount为0自然什么都渲染不出来
  • 接口响应数据你只做了打印,完全没执行JSON转CarDetails模型的步骤,数据拿到就丢了
修复方案

1. 改造接口请求方法,补全数据解析逻辑

把signInData的返回值改成Future<List<CarDetails>>,请求成功后先解析数据再返回,不要在请求方法里直接写跳页逻辑:

Future<List<CarDetails>> signInData([data]) async {
    final prefs = await SharedPreferences.getInstance();
    final String? token = prefs.getString('token');
    List<CarDetails> carList = [];

    try {
      Response response = await _dio.post('$_baseUrl/api/gateway',
          data: {
            "ClientPackageId": "0cdd231a-d7ad-4a68-a934-d373affb5100",
            "PlatformId": "ios",
            "ClientUserId": "AhmedOmar",
            "VinNumber": VINumber
          },
          options: Options(headers: {
            "Content-Type": "application/json",
            "Authorization": "Bearer $token",
          }));
      debugPrint(response.data.toString());
      debugPrint('请求状态码:${response.statusCode}');
      if (response.statusCode == 200) {
        // 注意:这里取列表的字段路径要和你实际接口返回结构对齐,比如接口直接返回数组就写response.data as List,如果是包在data字段里就按下面的写法
        List responseData = response.data['data'] as List;
        carList = responseData.map((item) => CarDetails.fromJson(item)).toList();
      } else if (response.statusCode == 500) {
        await getToken();
        carList = await signInData(data);
      }
    } catch (e) {
      debugPrint('请求报错:$e');
    }
    return carList;
  }

2. 选一种方式给结果页传递/加载数据

方式一:跳页时直接传入解析好的数据

接口请求拿到carList之后,跳页时把数据当参数传给ResultsPage:

// 原来写在请求成功后的跳页逻辑改成这样
List<CarDetails> carList = await signInData();
if(carList.isNotEmpty && mounted) {
  Navigator.of(context).pushReplacement(
    MaterialPageRoute(
      builder: (context) => ResultsPage(carList: carList),
    ),
  );
}

对应修改ResultsPage的代码接收参数:

class ResultsPage extends StatefulWidget {
  final List<CarDetails> carList;
  const ResultsPage({Key? key, required this.carList}) : super(key: key);

  @override
  _ResultsPageState createState() => _ResultsPageState();
}

class _ResultsPageState extends State<ResultsPage> {
  late List<CarDetails> objectList;

  @override
  void initState() {
    super.initState();
    objectList = widget.carList;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        children: [
          Expanded(
            // 这里shrinkWrap: true可以删掉,Expanded子组件占满剩余空间,开shrinkWrap反而冗余
            child: ListView.builder(
              itemCount: objectList.length,
              itemBuilder: (context, index) {
                return Padding(
                  padding: const EdgeInsets.all(10),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      const Text("Make"),
                      Text(objectList[index].make ?? ''),
                    ],
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

方式二:直接在ResultsPage初始化时拉取数据

不想传参的话就把请求逻辑放到结果页里,加载完调用setState刷新:

class _ResultsPageState extends State<ResultsPage> {
  List<CarDetails> objectList = [];
  bool isLoading = true;

  @override
  void initState() {
    super.initState();
    _loadCarData();
  }

  Future<void> _loadCarData() async {
    objectList = await signInData();
    isLoading = false;
    if(mounted) setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: isLoading 
        ? const Center(child: CircularProgressIndicator())
        : Column(
            children: [
              Expanded(
                child: ListView.builder(
                  itemCount: objectList.length,
                  itemBuilder: (context, index) {
                    return Padding(
                      padding: const EdgeInsets.all(10),
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          const Text("Make"),
                          Text(objectList[index].make ?? ''),
                        ],
                      ),
                    );
                  },
                ),
              ),
            ],
          ),
    );
  }
}

3. 其他要改的小问题

  • 数据模型里fueType是拼写错误,应该是fuelType,对应fromJson里的key也要确认是不是fuel_type,不然这个字段永远取不到值
  • 用可空类型的字段做Text组件入参的时候,别直接调toString(),加个空判断给默认空字符串,避免字段为null的时候显示"null"文本
  • 异步更新UI前一定要判断mounted属性,避免组件销毁后调用setState触发内存泄漏和报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 20:27:24