Flutter中ListView调用API后仅显示CircularProgressIndicator白屏问题修复求助
问题修复方案:Flutter ListView 调用API后白屏加载不结束
我帮你定位到了问题的核心——counter变量的赋值顺序错误,导致它始终为null,页面永远无法触发ListView的渲染,一直停留在加载状态。下面详细拆解问题并给出修复方案:
问题根源分析
在你的callHaber方法中,你先尝试用旧的haberResult(此时还是null)去赋值counter,之后才更新haberResult:
setState(() { counter = haberResult?.rss.channel.item.length; // 这时候haberResult还是null,counter会变成null haberResult = rss; });
再加上你用counter != null作为ListView的显示条件,这就导致ListView永远不会被渲染,页面一直显示CircularProgressIndicator。另外if(mounted);后面多了个分号,这行代码完全没有生效,属于无效写法。
修复步骤
方案1:调整赋值顺序(最小改动)
先更新haberResult,再用新数据赋值counter,同时去掉多余的分号:
Future callHaber() async { try{ final response = await http.get(url); if(response.statusCode == 200){ var rss = economylistXmlFromJson(response.body); if(mounted){ // 去掉多余的分号 setState(() { haberResult = rss; // 先更新数据源 counter = haberResult?.rss.channel.item.length; // 再基于新数据获取长度 }); } return rss; } else { print('请求失败,状态码:${response.statusCode}'); } } catch(e) { print('请求出错:${e.toString()}'); } }
方案2:移除counter变量(更简洁健壮)
其实完全不需要额外维护counter变量,直接用haberResult的数据长度作为ListView的itemCount,这样能避免变量同步问题:
修改build方法中的body部分:
body: Center( child: Padding( padding: const EdgeInsets.all(8.0), child: haberResult != null ? ListView.builder( itemCount: haberResult!.rss.channel.item.length, itemBuilder: (context, index){ final newsItem = haberResult!.rss.channel.item[index]; return Card( child: ListTile( title: Text(newsItem.title ?? ""), onTap: () => Navigator.push( context, MaterialPageRoute(builder: (context) => HaberDetailScreen( subtitle: newsItem.title ?? "", title: newsItem.description ?? "", )), ), ), ); }) : const Center(child: CircularProgressIndicator()), ), ),
方案3:使用FutureBuilder(推荐最佳实践)
手动维护haberResult和状态容易出错,用FutureBuilder可以自动处理异步请求的各种状态(加载中、成功、失败),代码更简洁健壮:
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( centerTitle: false, automaticallyImplyLeading: false, title: const Text('Ekonomi Haberleri'), ), body: FutureBuilder<EconomylistXml>( future: callHaber(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center(child: Text('加载出错:${snapshot.error}')); } else if (!snapshot.hasData || snapshot.data?.rss.channel.item.isEmpty == true) { return const Center(child: Text('没有找到新闻数据')); } else { final newsItems = snapshot.data!.rss.channel.item; return Padding( padding: const EdgeInsets.all(8.0), child: ListView.builder( itemCount: newsItems.length, itemBuilder: (context, index) { final item = newsItems[index]; return Card( child: ListTile( title: Text(item.title ?? ""), onTap: () => Navigator.push( context, MaterialPageRoute(builder: (context) => HaberDetailScreen( subtitle: item.title ?? "", title: item.description ?? "", )), ), ), ); }, ), ); } }, ), ); }
使用这个方案后,你可以移除haberResult和counter变量,callHaber方法只需返回请求结果即可,不用再手动调用setState。
额外注意事项
- 确保API返回的JSON结构和你的数据模型完全匹配,比如
rss.channel.item确实是数组类型,避免解析后出现空列表的情况。 - 记得在
initState中初始化ScrollController:controller = ScrollController();,避免空安全警告。 - 可以添加网络请求失败的UI提示,让用户知道发生了什么,而不是一直显示加载动画。
内容的提问来源于stack exchange,提问作者Mıktad Tahir Durak
相关产品推荐
相关产品推荐

