Flutter网络请求获取数据失败,FutureBuilder显示异常求助
Flutter网络请求与FutureBuilder问题排查
问题概述
- 按Flutter官方文档实现网络请求后,数据无法正常显示,怀疑问题出在FutureBuilder中,不会正确实现try-catch错误处理
- 类声明级别使用
late Future futurePrayer;时,数据能显示但出现调用错误;添加泛型late Future<Prayer> futurePrayer;后错误消失,但无数据展示 - 当前触发
NoSuchMethodError: 'call'错误,提示“对象没有实例方法'call'”

相关代码
FutureBuilder代码
FutureBuilder( future: futurePrayer, builder: (context, snapshot) { if (snapshot.hasData) { // TODO: fix NoSuchMethodError: 'call // Dynamic call of object has no instance method 'call'. return Text(snapshot.data.ashar()); } else if (snapshot.hasError) { return Text('${snapshot.error}'); } // By default, show a loading spinner. return const CircularProgressIndicator(); } ),
ApiBaseHelper代码
Future<Prayer> ApiBaseHelper() async { final response = await http .get(Uri.parse('https://api.myquran.com/v2/sholat/jadwal/1420/2025-01-05')); if (response.statusCode == 200) { // If the server did return a 200 OK response, // then parse the JSON. return Prayer.fromJson(jsonDecode(response.body) as Map<String, dynamic>); } else { // If the server did not return a 200 OK response, // then throw an exception. await ApiBaseHelper().catchError(print); throw Exception('Failed to load album'); } }
Prayer数据类代码
// this class is not used yet class PrayerResponse { List<String>? prayerTime; PrayerResponse({ required this.prayerTime, }); PrayerResponse.fromJson(Map<String, dynamic> json) { prayerTime = json['data']['jadwal']; } } class Prayer { final int id; final String lokasi; final String daerah; final String ashar; Prayer( { required this.id, required this.lokasi, required this.daerah, required this.ashar, } ); factory Prayer.fromJson(Map<String, dynamic> json) { return Prayer( id : json['data']['id'], lokasi : json['data']['lokasi'], daerah : json['data']['daerah'], ashar : json['data']['jadwal']['ashar'], ); } }
问题解决步骤
1. 修复NoSuchMethodError: 'call'错误
错误根源是将String属性当作方法调用:snapshot.data.ashar()中,ashar是Prayer类的String成员变量,不是方法,因此不需要加括号,改为:
return Text(snapshot.data.ashar);
如果使用泛型Future<Prayer>,建议给FutureBuilder指定泛型类型,避免类型转换问题:
FutureBuilder<Prayer>( future: futurePrayer, builder: (context, snapshot) { if (snapshot.hasData) { return Text(snapshot.data!.ashar); // 用!确保非空,或用?处理空值 } // ... 其他代码 } )
2. 修正ApiBaseHelper的错误处理与命名
- Dart函数名应遵循小驼峰命名规范,把
ApiBaseHelper改为apiBaseHelper - 移除错误分支中的递归调用
await ApiBaseHelper().catchError(print);,这会导致无限递归,直接抛出异常即可,同时建议添加try-catch包裹请求逻辑:
Future<Prayer> apiBaseHelper() async { try { final response = await http.get(Uri.parse('https://api.myquran.com/v2/sholat/jadwal/1420/2025-01-05')); if (response.statusCode == 200) { return Prayer.fromJson(jsonDecode(response.body) as Map<String, dynamic>); } else { throw Exception('请求失败,状态码:${response.statusCode}'); } } catch (e) { print('网络请求错误:$e'); throw Exception('加载祈祷时间失败'); } }
3. 正确初始化futurePrayer
使用泛型late Future<Prayer> futurePrayer;时,必须在合适的时机(如initState)初始化,避免每次build都重新发起请求:
late Future<Prayer> futurePrayer; @override void initState() { super.initState(); futurePrayer = apiBaseHelper(); // 调用请求函数,赋值给futurePrayer }
如果直接赋值futurePrayer = apiBaseHelper(不带括号),会把函数本身赋值给变量,而不是执行函数返回的Future,这会导致无数据展示。
4. FutureBuilder中的错误处理优化
可以在builder中更细致地处理快照状态,比如区分loading、error、success状态:
FutureBuilder<Prayer>( future: futurePrayer, builder: (context, snapshot) { switch (snapshot.connectionState) { case ConnectionState.waiting: return const CircularProgressIndicator(); case ConnectionState.done: if (snapshot.hasData) { return Text(snapshot.data!.ashar); } else if (snapshot.hasError) { return Text('加载失败:${snapshot.error}'); } default: return const Text('未知状态'); } }, )
内容的提问来源于stack exchange,提问作者shotmeinthehead
相关产品推荐
相关产品推荐

