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

Flutter中API数据已获取但ListView不显示,求问题排查

API返回正常但ListView无法显示数据

我正在尝试将API返回的数据展示在ListView中,已通过控制台确认API返回200成功响应且数据正常,但UI界面无法显示数据。想请教是否存在遗漏或代码错误,以下是我的实现代码:

API请求代码

class ListDosenProvider extends ChangeNotifier {
  static Future<List<ModelDosen>> getDosen() async {
    String url = Constant.baseURL;
    String token = await UtilSharedPreferences.getToken();
    final response = await http.get(
      Uri.parse(
        '$url/auth/mhs_siakad/dosen',
      ),
      headers: {
        'Authorization': 'Bearer $token',
      },
    );
    print(response.statusCode);
    print(response.body);
    if (response.statusCode == 200) {
      final List result = json.decode(response.body);
      return result.map((e) => ModelDosen.fromJson(e)).toList();
      // return ModelDosen.fromJson(jsonDecode(response.body));
    } else {
      throw Exception();
    }
  }
}

Widget调用代码

import 'package:flutter/material.dart';
import '../../../models/dosen/dosen_model.dart';
import '../../../provider/dosen/dosen_provider.dart';
import '../../../theme.dart';
import '../../../widgets/custom_appbar.dart';

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

  @override
  State<DosenPage> createState() => _DosenPageState();
}

class _DosenPageState extends State<DosenPage> {
  List<Datum> data = [];

  //  @override
  // void initState() {
  //   super.initState();
  //   fetchData();
  // }

  // fetchData() async {
  //   final apiResponse = await ListDosenProvider().getDosen() ??;
  //   setState(() {
  //     data = (apiResponse.data!);
  //   });
  // }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: PreferredSize(
        preferredSize: const Size.fromHeight(kToolbarHeight),
        child: CustomAppbar(
          title: 'Dosen',
        ),
      ),
      body: Center(
        child: FutureBuilder<List<ModelDosen>>(
          future: ListDosenProvider.getDosen(),
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return Expanded(
                child: ListView.builder(
                  itemCount: snapshot.data!.length,
                  itemBuilder: (context, index) {
                    return Container(
                      width: MediaQuery.of(context).size.width,
                      decoration: BoxDecoration(
                        color: Colors.white,
                        borderRadius: const BorderRadius.all(
                          Radius.circular(8),
                        ),
                        boxShadow: [
                          BoxShadow(
                            color: Colors.grey.withOpacity(0.2),
                            spreadRadius: 1,
                            blurRadius: 9,
                            offset: const Offset(
                                1, 2), // changes position of shadow
                          ),
                        ],
                      ),
                      child: Padding(
                        padding: const EdgeInsets.all(14),
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: [
                            Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: [
                                Text(
                                  data[index].name.toString(),
                                  style: bold6,
                                ),
                                Text(
                                  data[index].prodi.toString(),
                                  style: regular6,
                                ),
                                const SizedBox(
                                  height: 12,
                                ),
                                Row(
                                  children: [
                                    SizedBox(
                                      width: 94,
                                      height: 32,
                                      child: TextButton(
                                        onPressed: () {},
                                        style: TextButton.styleFrom(
                                          backgroundColor:
                                              const Color(0xffB3FFAE),
                                          shape: RoundedRectangleBorder(
                                            borderRadius:
                                                BorderRadius.circular(8),
                                          ),
                                        ),
                                        child: Text(
                                          "Email",
                                          style: boldButton1.copyWith(
                                            color: const Color(
                                              0xff379237,
                                            ),
                                          ),
                                        ),
                                      ),
                                    ),
                                    const SizedBox(
                                      width: 8,
                                    ),
                                    SizedBox(
                                      width: 94,
                                      height: 32,
                                      child: TextButton(
                                        onPressed: (() {}),
                                        style: TextButton.styleFrom(
                                          backgroundColor:
                                              const Color(0xffC5D5FF),
                                          shape: RoundedRectangleBorder(
                                            borderRadius:
                                                BorderRadius.circular(8),
                                          ),
                                        ),
                                        child: Text(
                                          "Detail",
                                          style: boldButton2.copyWith(
                                            color: primaryColor,
                                          ),
                                        ),
                                      ),
                                    ),
                                  ],
                                )
                              ],
                            ),
                            Image.asset(
                              'assets/images/user.png',
                              width: 50,
                            )
                          ],
                        ),
                      ),
                    );
                  },
                ),
              );
            } else {
              return CircularProgressIndicator(
                color: primaryColor,
              );
            }
          },
        ),
      ),
    );
  }
}

问题排查与修复方案

核心错误点

  • 未使用FutureBuilder的快照数据:你在ListView中调用data[index].name,但data列表始终是空的,没有从FutureBuilder的snapshot.data中赋值,应该直接使用快照里的返回数据。
  • 布局结构冲突:Expanded需要嵌套在Column/Row等弹性布局容器中,直接放在Center里会导致ListView无法获取可用空间,无法渲染内容。
  • 潜在类型不匹配:从注释的fetchData方法看,你之前可能期望ModelDosen包含data字段,但当前API解析逻辑是直接返回List<ModelDosen>,需确认ModelDosen结构是否和API返回数据匹配。

修改后的Widget核心代码

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: PreferredSize(
      preferredSize: const Size.fromHeight(kToolbarHeight),
      child: CustomAppbar(
        title: 'Dosen',
      ),
    ),
    // 移除外层Center,让FutureBuilder直接作为body子组件
    body: FutureBuilder<List<ModelDosen>>(
      future: ListDosenProvider.getDosen(),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return ListView.builder(
            padding: EdgeInsets.all(16),
            itemCount: snapshot.data!.length,
            itemBuilder: (context, index) {
              // 直接从快照中获取当前项数据
              final dosen = snapshot.data![index];
              return Container(
                width: MediaQuery.of(context).size.width,
                decoration: BoxDecoration(
                  color: Colors.white,
                  borderRadius: const BorderRadius.all(Radius.circular(8)),
                  boxShadow: [
                    BoxShadow(
                      color: Colors.grey.withOpacity(0.2),
                      spreadRadius: 1,
                      blurRadius: 9,
                      offset: const Offset(1, 2),
                    ),
                  ],
                ),
                margin: EdgeInsets.only(bottom: 12),
                child: Padding(
                  padding: const EdgeInsets.all(14),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            dosen.name.toString(),
                            style: bold6,
                          ),
                          Text(
                            dosen.prodi.toString(),
                            style: regular6,
                          ),
                          const SizedBox(height: 12),
                          Row(
                            children: [
                              SizedBox(
                                width: 94,
                                height: 32,
                                child: TextButton(
                                  onPressed: () {},
                                  style: TextButton.styleFrom(
                                    backgroundColor: const Color(0xffB3FFAE),
                                    shape: RoundedRectangleBorder(
                                      borderRadius: BorderRadius.circular(8),
                                    ),
                                  ),
                                  child: Text(
                                    "Email",
                                    style: boldButton1.copyWith(
                                      color: const Color(0xff379237),
                                    ),
                                  ),
                                ),
                              ),
                              const SizedBox(width: 8),
                              SizedBox(
                                width: 94,
                                height: 32,
                                child: TextButton(
                                  onPressed: () {},
                                  style: TextButton.styleFrom(
                                    backgroundColor: const Color(0xffC5D5FF),
                                    shape: RoundedRectangleBorder(
                                      borderRadius: BorderRadius.circular(8),
                                    ),
                                  ),
                                  child: Text(
                                    "Detail",
                                    style: boldButton2.copyWith(
                                      color: primaryColor,
                                    ),
                                  ),
                                ),
                              ),
                            ],
                          )
                        ],
                      ),
                      Image.asset(
                        'assets/images/user.png',
                        width: 50,
                      )
                    ],
                  ),
                ),
              );
            },
          );
        } else if (snapshot.hasError) {
          // 增加错误状态提示
          return Center(child: Text('加载失败: ${snapshot.error}'));
        } else {
          return Center(
            child: CircularProgressIndicator(color: primaryColor),
          );
        }
      },
    ),
  );
}

额外优化点

  • 移除了多余的Center和Expanded,让ListView自动占满可用空间
  • 增加列表项间距,提升UI可读性
  • 添加错误状态处理,方便排查加载失败问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 14:00:53