Flutter基于类模型集成API时ListView无法加载列表数据问题排查
Flutter 紧急联系人列表API集成ListView渲染异常排查
核心问题共3处,按影响优先级排序:
- UI层变量作用域错误:
getAllEmergenceyContacts方法内重新定义了局部变量books,接口返回的数据仅存在于方法作用域内,类层级的books列表始终为空,ListView拿不到有效数据。 - 异步请求后未触发UI刷新:接口请求是异步操作,数据返回后没有调用状态刷新方法,UI不会主动更新渲染列表。
- 数据模型字段映射错位:
fromJson和toJson方法内字段和接口返回值对应关系写反,后续渲染会出现字段值错乱问题。 - 补充说明:控制台打印
[Instance of 'Book', Instance of 'Book']是Dart打印自定义类实例的默认输出,不是数据拉取失败,属于正常现象。
修正后的数据模型Book类
修正字段映射关系,增加空安全兼容,符合Dart命名规范:
class Book { final int id; final String phone; final String name; final String relation; final String updatedAt; final String createdAt; final int userId; final String? image; // 接口返回image字段,做可空兼容 Book({ required this.id, required this.name, required this.phone, required this.relation, required this.createdAt, this.image, required this.updatedAt, required this.userId, }); factory Book.fromJson(Map<String, dynamic> json) => Book( id: json['id'] as int, // 对应接口返回的联系人主键ID name: json['contact_person'] as String, // contact_person为联系人姓名字段 relation: json['relation'] as String, phone: json['phone'] as String, updatedAt: json['updated_at'] as String, createdAt: json['created_at'] as String, userId: json['user_id'] as int, // 对应接口返回的所属用户ID image: json['image'] as String?, ); Map<String, dynamic> toJson() => { 'id': id, 'user_id': userId, 'contact_person': name, 'relation': relation, 'phone': phone, 'image': image, 'created_at': createdAt, 'updated_at': updatedAt, }; // 可选:重写toString方法方便调试打印实例内容 @override String toString() { return 'Book(id: $id, name: $name, phone: $phone, relation: $relation, userId: $userId)'; } }
修正后的接口请求方法
简化循环逻辑,增加空值兜底,避免变量重名引发的逻辑错误:
Future<List<Book>> getBook() async { List<Book> bookList = []; Map<String, String> headers = { "Content-type": "application/json", 'Authorization': 'Bearer $token', }; var url = Uri.parse(ApiPath.getAllEmergenceyContactUrl); final response = await http.get(url, headers: headers); if (response.statusCode == 200) { Map<String, dynamic> resMap = json.decode(response.body); // 接口无user字段时返回空数组做兜底 List<dynamic> userList = resMap["user"] ?? []; // 用内置map方法转换替代手写for循环,减少出错概率 bookList = userList .map((item) => Book.fromJson(item as Map<String, dynamic>)) .toList(); return bookList; } else { throw Exception('获取紧急联系人列表失败'); } }
修正后的UI层调用逻辑(以StatefulWidget为例)
修复变量作用域问题,增加加载态与空态提示,异步请求完成后主动刷新UI:
// 状态类内定义的全局变量 List<Book> books = []; bool isLoading = false; @override void initState() { super.initState(); // 页面初始化时拉取数据 getAllEmergenceyContacts(); } Future<void> getAllEmergenceyContacts() async { // 进入加载状态 setState(() { isLoading = true; }); try { // 直接给类层级的books变量赋值,不要在方法内重新定义同名变量 books = await services.getBook(); } catch (e) { debugPrint('拉取联系人失败: $e'); // 此处可增加toast等错误提示 } finally { // 请求完成后刷新UI setState(() { isLoading = false; }); } } // 页面build方法内的列表示例 @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('紧急联系人')), body: isLoading ? const Center(child: CircularProgressIndicator()) : books.isEmpty ? const Center(child: Text('暂无联系人数据')) : ListView.builder( itemCount: books.length, itemBuilder: (context, index) { final item = books[index]; return ListTile( title: Text(item.name), subtitle: Text('关系:${item.relation}\n电话:${item.phone}'), ); }, ), ); }
内容的提问来源于stack exchange,提问作者sarakhan
相关产品推荐
相关产品推荐

