Flutter API返回数据正常但FutureBuilder的snapshot.hasData始终为false
问题原因
- API返回结构与解析逻辑不匹配
你调用的接口返回的是单个User对象(外层是{}包裹的JSON对象),但你在getUser方法中直接将json.decode(response.body)的结果作为列表调用map方法,解析逻辑直接抛出异常,Future进入错误分支,因此snapshot.hasData始终为false。 - 模型类字段类型不匹配
API返回的IdNumber、PassportNumber、BirthCertNo都是字符串类型(示例中IdNumber是"000000",PassportNumber是空字符串),但你的User模型类将这三个字段定义为int类型,类型转换时会抛出异常,进一步导致解析失败。 - FutureBuilder判断逻辑错误
snapshot.hasData是布尔类型,只能是true或false,你写的if (snapshot.hasData == null)逻辑永远不成立,即使解析失败也不会走到你预期的无数据分支,也无法正确捕获加载状态。
修复方案
1. 修正User模型类字段类型
class User { User({ this.indexNo, this.name, this.idNumber, this.passportNumber, this.birthCertNo, }); String indexNo; String name; // 调整为字符串类型和接口返回对齐 String idNumber; String passportNumber; String birthCertNo; factory User.fromJson(Map<String, dynamic> json) => User( indexNo: json["IndexNo"], name: json["Name"], idNumber: json["IdNumber"], passportNumber: json["PassportNumber"], birthCertNo: json["BirthCertNo"], ); Map<String, dynamic> toJson() => { "indexNo": indexNo, "Name": name, "IdNumber": idNumber, "PassportNumber": passportNumber, "BirthCertNo": birthCertNo, }; }
2. 修正getUser解析逻辑
如果你要兼容现有List<User>的写法,把解析出的单个用户放到列表中返回即可:
Future<List<User>> getUser() async { var url = Uri.parse('https://xx-api.xxxxxxx.co.ke/api/auth/user'); var jwt = Globals.token; var response = await http .get(url, headers: {HttpHeaders.authorizationHeader: "Bearer $jwt"}); print(response.body); // 先解析单条用户数据,再封装到列表返回 var userJson = json.decode(response.body); User user = User.fromJson(userJson); return [user]; }
3. 修正FutureBuilder判断逻辑
FutureBuilder<List<User>>( future: _user, builder: (context, snapshot) { // 优先判断加载状态 if (snapshot.connectionState == ConnectionState.waiting) { return const CircularProgressIndicator(); } // 捕获错误 if (snapshot.hasError) { return Text("错误:${snapshot.error}"); } // 最后判断数据是否存在 if (!snapshot.hasData || snapshot.data.isEmpty) { return const Text('No data available'); } List<User> myUser = snapshot.data; return ListView.builder( itemCount: myUser.length, itemBuilder: (BuildContext context, int index) { return myUser[index].indexNo.contains(searchString) ? Card( child: Column( children: [ ListTile( enabled: true, onTap: () {}, title: Text(myUser[index].name), subtitle: Text(myUser[index].idNumber), ) ], ), ) : const SizedBox.shrink(); }); } )
内容的提问来源于stack exchange,提问作者tharnos_nos
相关产品推荐
相关产品推荐

