Flutter报错:'String'类型不是'index'的'int'子类型,求解决
解决Flutter中API列表展示的
type 'String' is not a subtype of type 'int' of 'index'错误 问题描述
我尝试从API获取数据并展示列表,但一直遇到错误:type 'String' is not a subtype of type 'int' of 'index'。已经排查过同类问题并尝试了各种方法,还是无法解决,希望得到帮助。
相关代码
页面逻辑代码
final List<Team> _teams = <Team>[]; Future<List<Team>> getTeams() async { final response = await http .get(Uri.parse('http://...'), headers: { 'Authorization': 'Basic ...', 'Content-Type': 'application/json', 'Accept': 'application/json' }); print('Response status: ${response.statusCode}'); print('Response body: ${response.body}'); if (response.statusCode == 200) { List<Team> model = List<Team>.from( json.decode(response.body)['data'].map((x) => Team.fromJson(x))); return model; } else { throw Exception('error occured'); } } class TeamsScreen extends StatefulWidget { const TeamsScreen({Key? key}) : super(key: key); @override State<StatefulWidget> createState() => _TeamsScreenState(); } class _TeamsScreenState extends State<TeamsScreen> { late Future<List<Team>> futureTeam; late SharedPreferences logindata; String? username; @override void initState() { super.initState(); initial(); futureTeam = getTeams(); } void initial() async { logindata = await SharedPreferences.getInstance(); setState(() { username = logindata.getString('username') ?? ''; }); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0Xfff7f7f5), appBar: AppBar( centerTitle: false, leadingWidth: 0, backgroundColor: Colors.white, toolbarHeight: 60.0, title: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ const Text( '...', style: TextStyle( color: Colors.black, fontFamily: 'Cera', fontWeight: FontWeight.bold, fontSize: 18, ), ), Text( '...', textAlign: TextAlign.left, style: const TextStyle( color: Colors.grey, fontFamily: 'Cera', fontSize: 12, ), ) ], ), ), body: Container( padding: const EdgeInsets.only( top: 25, left: 5, ), child: FutureBuilder<List<Team>>( future: futureTeam, builder: (context, AsyncSnapshot snapshot) { if (snapshot.hasData) { // var team = (snapshot.data as List<Team>).toList(); List<Team> team = snapshot.data; return ListView.builder( shrinkWrap: true, physics: const ClampingScrollPhysics(), padding: const EdgeInsets.only( top: 25, left: 5, ), itemCount: team.length, //+1 itemBuilder: (BuildContext context, int index) { return TeamWidget(_teams[index], (() { onTeamTap(context, index); })); }); } else if (snapshot.hasError) { logger.e('${snapshot.error}'); } return const Center( child: CircularProgressIndicator.adaptive(), ); }, ), )); } onTeamTap(BuildContext context, int index) { Navigator.push(context, MaterialPageRoute(builder: (context) => AthleteScreen(_teams[index]))); } }
Team模型代码
class Team { List<Team> teamFromJson(String str) => List<Team>.from(json.decode(str).map((x) => Team.fromJson(x))); String teamToJson(List<Team> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson()))); final TeamKey teamKey; final String teamName; final int hidden; final User user; final String depName; Team( {required this.teamKey, required this.teamName, required this.hidden, required this.user, required this.depName}); factory Team.fromJson(Map<String, dynamic> json) => Team( teamKey: TeamKey.fromJson(json['teamKey']), teamName: json['teamName'] as String, hidden: int.parse(json['hidden']), user: User.fromJson(json['user']), depName: json['depName'] as String, ); Map<String, dynamic> toJson() => { 'teamKey': teamKey, 'teamName': teamName, 'hidden': hidden.toString(), 'user': user, 'depName': depName, }; }
Postman返回的响应体
[ { "teamKey": { "depId": 1, "teamId": 1 }, "teamName": "..", "hidden": 0, "user": { "id": 1, "username": "...", "role": "..." }, "depName": "..." } ]
错误原因及修复方案
1. API响应解析错误(核心问题)
从Postman响应可以看到,接口直接返回的是数组格式的JSON,但你的getTeams方法里用了json.decode(response.body)['data']——数组类型只能用整数索引访问,用字符串'data'作为索引会直接抛出type 'String' is not a subtype of type 'int' of 'index'错误。
修复getTeams方法的解析逻辑:
Future<List<Team>> getTeams() async { final response = await http .get(Uri.parse('http://...'), headers: { 'Authorization': 'Basic ...', 'Content-Type': 'application/json', 'Accept': 'application/json' }); print('Response status: ${response.statusCode}'); print('Response body: ${response.body}'); if (response.statusCode == 200) { // 直接解析数组,不需要['data'] List<Team> model = List<Team>.from( json.decode(response.body).map((x) => Team.fromJson(x))); return model; } else { throw Exception('error occured'); } }
2. 列表数据引用错误
你的ListView.builder和onTeamTap方法中,错误地引用了全局空列表_teams,但实际获取到的数据存在snapshot.data对应的team列表中。这样会导致两个问题:一是展示空数据,二是当索引超出空列表范围时触发异常。
修复页面中的数据引用:
if (snapshot.hasData) { List<Team> team = snapshot.data; // 可选:如果需要全局保存数据,可以将team赋值给_teams setState(() { _teams.clear(); _teams.addAll(team); }); return ListView.builder( shrinkWrap: true, physics: const ClampingScrollPhysics(), padding: const EdgeInsets.only( top: 25, left: 5, ), itemCount: team.length, itemBuilder: (BuildContext context, int index) { // 用当前列表的team[index]替代_teams[index] return TeamWidget(team[index], (() { onTeamTap(context, index, team); })); }); } // 修改onTeamTap方法,传入当前数据列表 void onTeamTap(BuildContext context, int index, List<Team> team) { Navigator.push(context, MaterialPageRoute(builder: (context) => AthleteScreen(team[index]))); }
3. 模型类的潜在问题
你的Team.fromJson中,hidden字段用了int.parse(json['hidden']),但从响应看hidden本身就是数字类型,直接强转更安全,避免字符串转整数的异常:
factory Team.fromJson(Map<String, dynamic> json) => Team( teamKey: TeamKey.fromJson(json['teamKey']), teamName: json['teamName'] as String, // 直接强转为int,因为响应中hidden是数字 hidden: json['hidden'] as int, user: User.fromJson(json['user']), depName: json['depName'] as String, );
内容的提问来源于stack exchange,提问作者kate_3dev
相关产品推荐
相关产品推荐

