Flutter中数组结构API数据无法在ListView.builder展示问题排查
问题解决:Flutter数组结构API数据无法在ListView展示
问题背景
开发Flutter移动端应用,输入名称获取API数据。原本单对象结构的API能正常工作,但切换为返回数组结构的API后,页面仅显示头像图片,ListView无数据加载。尝试过FutureBuilder和GridViewBuilder均无效,怀疑问题出在API返回的数组结构处理上。
API示例
正常工作的单对象API
{"id":"Pw_wOwAmqDmB3slQO_8PkKXLoE56qnBk5f-qdW0fKVTfvAmm", "accountId":"_MkPpRhr6tK22xRT8TofYHPyACcmURn0cp-U9GbL1xTQzhRfvaw4ZF7P", "puuid":"RT0wLpw9fOUMgB4HUWDVoMi6_F20W4yhut5-q1bA7Izhl3dPjv5iF2JzqXkLQJYPtf2MBMcvooMmGA", "name":"Zeri outplay", "profileIconId":5610,"revisionDate":1669140463310, "summonerLevel":535}
无法正常工作的数组结构API
[{"leagueId":"e6a38c93-6037-4457-aa57-80a9a52be3ea", "queueType":"RANKED_SOLO_5x5", "tier":"PLATINUM","rank":"IV", "summonerId":"Pw_wOwAmqDmB3slQO_8PkKXLoE56qnBk5f-qdW0fKVTfvAmm", "summonerName":"Zeri outplay", "leaguePoints":0, "wins":75, "losses":56, "veteran":false, "inactive":false, "freshBlood":false, "hotStreak":false}, {"leagueId":"a21014e6-fa8f-4f07-b533-b09a10b88bbf", "queueType":"RANKED_FLEX_SR", "tier":"SILVER","rank":"II", "summonerId":"Pw_wOwAmqDmB3slQO_8PkKXLoE56qnBk5f-qdW0fKVTfvAmm", "summonerName":"Zeri outplay", "leaguePoints":1, "wins":15, "losses":5, "veteran":false, "inactive":false, "freshBlood":false, "hotStreak":true}]
现有代码
RemoteService.dart
class SummonerRankApi { static Future getSummonerRank(summonerid) { String link = 'https://euw1.api.riotgames.com/lol/league/v4/entries/by-summoner/$summonerid?api_key=$apiKey'; return http.get(Uri.parse(link)); } }
Home_page.dart
class SummonerProfileRoute extends StatefulWidget { String name, summonerId; int profileIconId; SummonerProfileRoute(this.name, this.summonerId, this.profileIconId); @override State<StatefulWidget> createState() { return _SummonerProfileRouteState(this.name, this.summonerId, this.profileIconId); }} class _SummonerProfileRouteState extends State<SummonerProfileRoute> { List<SummonerRank> SummonerRankList = <SummonerRank>[]; void getSummonerRankfromApi() async { SummonerRankApi.getSummonerRank(summonerId).then((response) { setState(() { Iterable list = json.decode(response.body); SummonerRankList = list.map((model) => SummonerRank.fromJson(model)).toList(); }); }); } String name, summonerId; int profileIconId; _SummonerProfileRouteState(this.name, this.summonerId, this.profileIconId); @override void initState() { super.initState(); getSummonerRankfromApi(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Second Route'), ), body: Center( child: Column( children: [ Image( image: NetworkImage('https://ddragon.leagueoflegends.com/cdn/12.22.1/img/profileicon/$profileIconId.png'), height: 100, width: 100, ), ListView.builder( itemCount: SummonerRankList.length, itemBuilder: (context, index) { return ListTile( title: Text(SummonerRankList[index].tier), subtitle: Text(SummonerRankList[index].summonerName), ); }), ], ) ), ); } }
summoner.dart
class SummonerRank { String leagueId; String queueType; String tier; String rank; String summonerId; String summonerName; int leaguePoints; int wins; int losses; bool veteran; bool inactive; bool freshBlood; bool hotStreak; SummonerRank.fromJson(Map json) : leagueId = json['leagueId'], queueType = json['queueType'], tier = json['tier'], rank = json['rank'], summonerId = json['summonerId'], summonerName = json['summonerName'], leaguePoints = json['leaguePoints'], wins = json['wins'], losses = json['losses'], veteran = json['veteran'], inactive = json['inactive'], freshBlood = json['freshBlood'], hotStreak = json['hotStreak']; Map toJson() { return {'leagueId': leagueId, 'queueType': queueType, 'tier': tier, 'rank': rank, 'summonerId': summonerId, 'summonerName': summonerName, 'leaguePoints': leaguePoints, 'wins': wins, 'losses': losses, 'veteran': veteran, 'inactive': inactive, 'freshBlood': freshBlood, 'hotStreak': hotStreak}; } }
问题原因及解决方案
核心问题
ListView放在Column中没有设置高度约束,且未添加shrinkWrap: true或包裹在Expanded组件内,导致ListView无法正常渲染空间。和API数组结构无关,是布局问题。
修复步骤
- 给ListView添加约束:在Column中,用
Expanded包裹ListView,让它占据剩余空间;或者设置shrinkWrap: true并指定固定高度。 - 优化API请求处理:添加错误捕获,避免请求失败时无反馈。
修改后的Home_page.dart关键代码
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Second Route'), ), body: Column( children: [ Image( image: NetworkImage('https://ddragon.leagueoflegends.com/cdn/12.22.1/img/profileicon/$profileIconId.png'), height: 100, width: 100, ), // 用Expanded包裹ListView,让它占据剩余空间 Expanded( child: ListView.builder( itemCount: SummonerRankList.length, itemBuilder: (context, index) { return ListTile( title: Text(SummonerRankList[index].tier), subtitle: Text(SummonerRankList[index].summonerName), ); }), ), ], ), ); }
额外优化:添加错误处理和加载状态
void getSummonerRankfromApi() async { try { final response = await SummonerRankApi.getSummonerRank(summonerId); if (response.statusCode == 200) { setState(() { Iterable list = json.decode(response.body); SummonerRankList = list.map((model) => SummonerRank.fromJson(model)).toList(); }); } else { // 处理请求失败情况 print('请求失败,状态码:${response.statusCode}'); } } catch (e) { print('请求异常:$e'); } }
内容的提问来源于stack exchange,提问作者moosiker
相关产品推荐
相关产品推荐

