Flutter使用HTTP Get获取数据库数据报错,求可运行示例
问题:Flutter HTTP Get请求报错:
type 'String' is not a subtype of type 'int' of 'index' 执行Flutter的HTTP Get请求从数据库获取数据时,出现以下错误:
E/flutter (15407): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
我的代码:
// ignore_for_file: no_leading_underscores_for_local_identifiers, prefer_typing_uninitialized_variables import 'dart:convert'; import 'package:apetit_project/models/app_user.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import '../models/auth_form_data.dart'; import 'package:http/http.dart' as http; class AuthForm extends StatefulWidget { final void Function(AuthFormData) onSubmit; const AuthForm({ Key? key, required widget.onSubmit, }) : super(key: key); @override State<AuthForm> createState() => _AuthFormState(); } class _AuthFormState extends State<AuthForm> { TextEditingController _emailController = TextEditingController(); TextEditingController _passwordController = TextEditingController(); final _formKey = GlobalKey<FormState>(); final _formData = AuthFormData(); String _teste = '[]'; final _url = 'http://172.16.30.120:8080/ords/apiteste/integrafoods/users'; @override void dispose() { _emailController.dispose(); _passwordController.dispose(); super.dispose(); } bool isLogin = true; late String title; late String actionButton; late String toggleButton; void _submit() { final isValid = _formKey.currentState?.validate() ?? false; if (!isValid) return; widget.onSubmit(_formData); } Future<void> _loadUsers() async { final response = await http.get(Uri.parse(_url)); Map<String, dynamic> data = jsonDecode(response.body); data.forEach( (userId, userData) { _teste = userData['nome']; }, ); print(_teste); // $_url/${newComment.comment} } @override Widget build(BuildContext context) { return Scaffold( body: Container( decoration: const BoxDecoration( image: DecorationImage( image: AssetImage('assets/images/Login.png'), fit: BoxFit.cover, alignment: Alignment.center, ), ), child: Container( margin: const EdgeInsets.only(bottom: 30), child: Padding( padding: const EdgeInsets.all(20), child: Form( key: _formKey, child: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ if (_formData.isSignup) TextFormField( key: const ValueKey('Nome'), initialValue: _formData.name, onChanged: (name) => _formData.name = name, decoration: InputDecoration( enabledBorder: OutlineInputBorder( borderSide: const BorderSide(color: Colors.black), borderRadius: BorderRadius.circular(30)), focusedBorder: OutlineInputBorder( borderSide: const BorderSide(color: Colors.black), borderRadius: BorderRadius.circular(30)), focusedErrorBorder: OutlineInputBorder( borderSide: const BorderSide(color: Colors.black), borderRadius: BorderRadius.circular(30)), labelText: 'Nome', labelStyle: const TextStyle(color: Colors.black), ), keyboardType: TextInputType.emailAddress, ), if (_formData.isLogin) TextFormField( // controller: _emailController, key: const ValueKey('Email'), initialValue: _formData.email, onChanged: (email) => _formData.email = email, decoration: InputDecoration( enabledBorder: OutlineInputBorder( borderSide: const BorderSide(color: Colors.black), borderRadius: BorderRadius.circular(30)), focusedBorder: OutlineInputBorder( borderSide: const BorderSide(color: Colors.black), borderRadius: BorderRadius.circular(30)), focusedErrorBorder: OutlineInputBorder( borderSide: const BorderSide(color: Colors.black), borderRadius: BorderRadius.circular(30)), prefixIcon: Image.asset( 'assets/images/email_icon.png', scale: 6, color: Colors.black, ), labelText: 'Email', labelStyle: const TextStyle(color: Colors.black), ), validator: (_email) { final email = _email ?? ''; if (!email.contains('@')) { return 'E-mail informado não é válido.'; } return null; }, keyboardType: TextInputType.emailAddress, ), const SizedBox( height: 20, ), if (_formData.isLogin) TextFormField( // controller: _passwordController, key: const ValueKey('password'), initialValue: _formData.password, onChanged: (password) => _formData.password = password, style: const TextStyle(color: Colors.black), obscureText: true, decoration: InputDecoration( enabledBorder: OutlineInputBorder( borderSide: const BorderSide(color: Colors.black), borderRadius: BorderRadius.circular(30)), focusedBorder: OutlineInputBorder( borderSide: const BorderSide(color: Colors.black), borderRadius: BorderRadius.circular(30)), errorBorder: OutlineInputBorder( borderSide: const BorderSide(color: Colors.black), borderRadius: BorderRadius.circular(30)), focusedErrorBorder: OutlineInputBorder( borderSide: const BorderSide(color: Colors.black), borderRadius: BorderRadius.circular(30)), prefixIcon: Padding( padding: const EdgeInsets.only(left: 18, right: 18), child: Image.asset( 'assets/images/password_icon.png', scale: 6, color: Colors.black, ), ), labelText: 'Senha', labelStyle: const TextStyle(color: Colors.black)), validator: (_password) { final password = _password ?? ''; if (password.length < 6) { return 'Senha deve ter no mínimo 6 caracteres'; } return null; }, ), const SizedBox( height: 20, ), SizedBox( width: double.infinity, child: ElevatedButton( // onPressed: _signInUser, onPressed: _loadUsers, style: ButtonStyle( shape: MaterialStateProperty.all(RoundedRectangleBorder( borderRadius: BorderRadius.circular(30), )), padding: MaterialStateProperty.all(const EdgeInsets.all(15)), backgroundColor: MaterialStateProperty.all( Theme.of(context).colorScheme.secondary), ), child: Text( _formData.isLogin ? 'Entrar' : 'Cadastrar', style: const TextStyle( color: Colors.black, fontFamily: 'Raleway', fontWeight: FontWeight.bold), ), ), ), TextButton( onPressed: () { setState(() { _formData.toggleAuthMode(); }); }, child: Text( _formData.isLogin ? 'Criar uma nova conta?' : 'Já possui conta?', ), ), ], ), ), ), ), ), ); } Future _signInUser() async { await FirebaseAuth.instance.signInWithEmailAndPassword( email: _emailController.text, password: _passwordController.text, ); } }
接口返回的JSON数据:
{ "items": [ { "id": 1, "login": "1234567", "nome": "Ricardo", "situacao": "A", "telefone": "(14) 99797-5621", "senha": "124578", "dt_inclusao": null, "usu_inclusao": null, "dt_alteracao": null, "usu_alteracao": null } ], "hasMore": false, "limit": 25, "offset": 0, "count": 1, "links": [ { "rel": "self", "href": "http://172.16.30.120:8080/ords/apiteste/integrafoods/users" }, { "rel": "describedby", "href": "http://172.16.30.120:8080/ords/apiteste/metadata-catalog/integrafoods/item" }, { "rel": "first", "href": "http://172.16.30.120:8080/ords/apiteste/integrafoods/users" } ] }
需要获取可运行的示例,理解问题并解决错误。
解决方法
错误原因
报错的核心问题在于_loadUsers方法中的数据解析逻辑错误:
- 接口返回的JSON中,用户数据嵌套在
items数组里,而你直接遍历整个顶层Map,当遍历到hasMore、limit等非数组类型的字段时,尝试用userData['nome']访问字符串/数值类型的value,就会抛出String is not a subtype of int的错误(因为这些value不是Map,用[]索引时会把字符串当成int索引来处理)。
修复后的_loadUsers方法
Future<void> _loadUsers() async { final response = await http.get(Uri.parse(_url)); Map<String, dynamic> data = jsonDecode(response.body); // 先取出items数组,再遍历其中的用户对象 List<dynamic> users = data['items']; for (var userData in users) { _teste = userData['nome']; print(_teste); // 会打印出"Ricardo" } }
完整可运行的修改后代码
只需要替换原代码中的_loadUsers方法即可,其余代码保持不变。如果需要增加错误处理和UI更新,可使用以下版本:
Future<void> _loadUsers() async { final response = await http.get(Uri.parse(_url)); if (response.statusCode == 200) { Map<String, dynamic> data = jsonDecode(response.body); List<dynamic> users = data['items']; // 遍历所有用户并打印信息 for (var user in users) { print("用户名: ${user['nome']}, 登录名: ${user['login']}"); _teste = user['nome']; // 保存最后一个用户的名字到_teste } setState(() {}); // 如果需要更新UI,调用setState刷新 } else { print("请求失败,状态码: ${response.statusCode}"); } }
额外优化建议
强类型解析:定义用户模型类,将JSON数据解析为强类型对象,提升代码可读性和维护性
// 假设AppUser类定义如下 class AppUser { final int id; final String login; final String nome; final String situacao; final String telefone; AppUser({ required this.id, required this.login, required this.nome, required this.situacao, required this.telefone, }); factory AppUser.fromJson(Map<String, dynamic> json) { return AppUser( id: json['id'], login: json['login'], nome: json['nome'], situacao: json['situacao'], telefone: json['telefone'], ); } }修改解析逻辑:
List<AppUser> userList = users.map((user) => AppUser.fromJson(user)).toList();异常捕获:添加try-catch块处理网络请求和JSON解析中的异常,避免崩溃
内容的提问来源于stack exchange,提问作者pedro.curti
相关产品推荐
相关产品推荐

