Flutter开发:多API端点下实现联赛类关联足球赛事实例列表的最优方案
实现带赛事列表的可展开联赛列表的最优方案
我来帮你一步步解决这个问题,从修改数据模型到整合API数据,再到优化方法逻辑:
1. 先修改League类,添加赛事列表属性
当然可以直接在League类里添加List<SoccerMatch>属性,建议初始化一个空列表避免空指针问题,同时更新构造函数和fromJson工厂方法:
class League { int id; String name; String country; String logoUrl; String flag; String season; // 添加赛事列表,初始化为空列表 List<SoccerMatch> matches; League( this.id, this.name, this.country, this.logoUrl, this.flag, this.season, // 构造函数里初始化matches this.matches = const [], ); factory League.fromJson(Map<String, dynamic> json) { return League( json['league']['id'], json['league']['name'], json['country']['name'], json['league']['logo'], json['country']['flag'], json['seasons'][0]['year'].toString(), // fromJson时先给空列表,后续再填充数据 [], ); } }
2. 优化getLeague方法,返回单个League实例
你提到当前返回列表不是最佳实践,因为根据leagueName和country参数,API应该只会返回唯一的联赛数据。我们可以调整方法返回Future<League?>(处理无数据的情况)或者Future<League>(确保有数据,无数据时抛出异常):
Future<League?> getLeague(String leagueName, String country) async { Response response = await get( Uri.parse( "${apiUrl}leagues?current=true&name=$leagueName&country=$country"), headers: headers); if (response.statusCode == 200) { var body = jsonDecode(response.body); List<dynamic> leagueList = body['response']; if (leagueList.isNotEmpty) { return League.fromJson(leagueList.first); } else { // 没有找到对应联赛时返回null return null; } } else { throw Exception('Error accessing API: ${response.statusCode}'); } }
如果你的业务场景中必须存在该联赛,也可以在leagueList为空时抛出异常,替换return null为throw Exception('League not found')。
3. 整合两个API的数据,给联赛填充赛事
这里有两种常用的实现方式,根据你的业务场景选择:
方式一:封装一个组合方法,一次性获取联赛+赛事
在SoccerApi里新增一个方法,先获取联赛,再根据联赛ID获取对应的赛事,最后赋值给League的matches属性:
Future<League?> getLeagueWithMatches(String leagueName, String country) async { try { // 先获取联赛信息 League? league = await getLeague(leagueName, country); if (league == null) return null; // 根据联赛ID获取赛事列表 List<SoccerMatch> matches = await getAllMatches(league.id); // 给联赛赋值赛事 league.matches = matches; return league; } catch (e) { throw Exception('Failed to fetch league with matches: $e'); } }
方式二:在ViewModel/UI层手动组合数据
如果你希望更灵活地控制加载时机(比如先展示联赛列表,用户点击展开时再加载赛事),可以在UI逻辑里先获取联赛,当用户触发展开操作时再调用getAllMatches,然后更新League的matches:
// 示例:在UI逻辑中 void loadLeagueMatches(League league) async { try { List<SoccerMatch> matches = await soccerApi.getAllMatches(league.id); setState(() { league.matches = matches; }); } catch (e) { // 处理加载失败的情况 print(e); } }
4. 额外的小优化:处理API返回的空值
注意到你的模型里有些字段可能为null(比如Goal的home/away可能还没有进球数据),建议修改类型为可空,并在fromJson时处理空值,避免运行时错误:
class Goal { String? home; String? away; Goal(this.home, this.away); factory Goal.fromJson(Map<String, dynamic> json) { return Goal( json['home']?.toString(), json['away']?.toString(), ); } }
这样当API返回null时,你的模型不会因为toString()调用而崩溃。
内容的提问来源于stack exchange,提问作者bragi
相关产品推荐
相关产品推荐

