Flutter中Get API请求无响应问题排查求助
问题:Flutter调用JSONPlaceholder API无响应,无控制台输出
在Flutter项目中调用JSONPlaceholder的Get接口获取用户数据,该接口在网页和Postman中均能正常返回数据,但代码里完全没响应,控制台也未打印任何调试日志。已通过QuickType生成对应数据模型,多次尝试仍无法解决,请求排查。
相关代码
HomeView代码
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import '../models/userModel.dart'; class HomeView extends StatefulWidget { const HomeView({Key? key}) : super(key: key); @override State<HomeView> createState() => _HomeViewState(); } class _HomeViewState extends State<HomeView> { // 创建空列表存储用户数据 List<Users> userDetails = []; // 从API获取用户数据的异步方法 Future<List<Users>> getUsers() async { print("api method calling"); final response = await http.get(Uri.parse("https://jsonplaceholder.typicode.com/users"),); print('api response check'); var data = jsonDecode(response.body.toString()); print('api data received'); if (response.statusCode == 200) { for (Map<String, dynamic> index in data) { userDetails.add(Users.fromJson(index)); } return userDetails; } else { return userDetails; } } @override Widget build(BuildContext context) { return FutureBuilder( future: getUsers(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { print('no connection error'); if (snapshot.hasData) { print('snapshot has data'); return ListView.builder( itemCount: 1, itemBuilder: (context, index) { return Container( margin: const EdgeInsets.all(10), height: 100, color: Colors.greenAccent, padding: const EdgeInsets.symmetric( vertical: 10, horizontal: 20), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: const [ Text('User Id : data'), Text('User Id : data'), Text('User Id : data'), Text('User Id : data'), ], ), ); }); } else { print('snapshot has no data'); return const Center( child: CircularProgressIndicator(), ); } } else { return const Center( child: Text("connection error"), ); } }); } }
数据模型代码
// To parse this JSON data, do // // final users = usersFromJson(jsonString); import 'dart:convert'; List<Users> usersFromJson(String str) => List<Users>.from(json.decode(str).map((x) => Users.fromJson(x))); String usersToJson(List<Users> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson()))); class Users { Users({ required this.id, required this.name, required this.username, required this.email, required this.address, required this.phone, required this.website, required this.company, }); int id; String name; String username; String email; Address address; String phone; String website; Company company; factory Users.fromJson(Map<String, dynamic> json) => Users( id: json["id"], name: json["name"], username: json["username"], email: json["email"], address: Address.fromJson(json["address"]), phone: json["phone"], website: json["website"], company: Company.fromJson(json["company"]), ); Map<String, dynamic> toJson() => { "id": id, "name": name, "username": username, "email": email, "address": address.toJson(), "phone": phone, "website": website, "company": company.toJson(), }; } class Address { Address({ required this.street, required this.suite, required this.city, required this.zipcode, required this.geo, }); String street; String suite; String city; String zipcode; Geo geo; factory Address.fromJson(Map<String, dynamic> json) => Address( street: json["street"], suite: json["suite"], city: json["city"], zipcode: json["zipcode"], geo: Geo.fromJson(json["geo"]), ); Map<String, dynamic> toJson() => { "street": street, "suite": suite, "city": city, "zipcode": zipcode, "geo": geo.toJson(), }; } class Geo { Geo({ required this.lat, required this.lng, }); String lat; String lng; factory Geo.fromJson(Map<String, dynamic> json) => Geo( lat: json["lat"], lng: json["lng"], ); Map<String, dynamic> toJson() => { "lat": lat, "lng": lng, }; } class Company { Company({ required this.name, required this.catchPhrase, required this.bs, }); String name; String catchPhrase; String bs; factory Company.fromJson(Map<String, dynamic> json) => Company( name: json["name"], catchPhrase: json["catchPhrase"], bs: json["bs"], ); Map<String, dynamic> toJson() => { "name": name, "catchPhrase": catchPhrase, "bs": bs, }; }
main.dart代码
import 'package:flutter/material.dart'; import 'package:responsive_login_ui/views/home_view.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( appBar: AppBar(title: Text('User Data From Api'),), body: HomeView() ), ); } }
问题排查与修复方案
1. 核心问题定位
- FutureBuilder重复发起请求:
build方法每次执行都会调用getUsers(),导致多次请求冲突,甚至引发状态异常 - 无异常捕获机制:
getUsers方法未处理网络请求、JSON解析时的异常,一旦出错会静默失败,控制台无日志输出 - ListView配置错误:
itemCount写死为1,无法展示全部数据;UI文本硬编码,未绑定实际接口返回数据 - 数据模型无空值处理:直接从JSON取字段,若接口返回空值会触发类型转换错误
2. 分步修复
修复1:将Future初始化移至initState
避免重复发起请求,保存Future引用:
class _HomeViewState extends State<HomeView> { List<Users> userDetails = []; late Future<List<Users>> _usersFuture; @override void initState() { super.initState(); _usersFuture = getUsers(); // 仅在初始化时发起一次请求 } @override Widget build(BuildContext context) { return FutureBuilder( future: _usersFuture, // 使用保存的Future引用 builder: (context, snapshot) { // builder逻辑不变 }); } }
修复2:给getUsers添加异常捕获
添加try-catch块,打印异常信息定位问题:
Future<List<Users>> getUsers() async { try { print("api method calling"); final response = await http.get(Uri.parse("https://jsonplaceholder.typicode.com/users")); print('api response status code: ${response.statusCode}'); if (response.statusCode == 200) { var data = jsonDecode(response.body.toString()); print('api data received, length: ${data.length}'); for (Map<String, dynamic> index in data) { userDetails.add(Users.fromJson(index)); } return userDetails; } else { print('api request failed, status code: ${response.statusCode}'); return userDetails; } } catch (e) { print('api request error: $e'); return userDetails; } }
修复3:修正ListView配置与数据绑定
使用实际数据长度作为itemCount,并绑定用户数据到UI:
if (snapshot.hasData) { print('snapshot has data, length: ${snapshot.data!.length}'); return ListView.builder( itemCount: snapshot.data!.length, itemBuilder: (context, index) { final user = snapshot.data![index]; return Container( margin: const EdgeInsets.all(10), height: 100, color: Colors.greenAccent, padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('User Id : ${user.id}'), Text('Name : ${user.name}'), Text('Email : ${user.email}'), Text('Username : ${user.username}'), ], ), ); }); }
修复4:优化数据模型的空值处理
给模型的fromJson方法添加空值默认值,避免类型错误:
// Users类示例,嵌套类如Address、Geo、Company同理修改 factory Users.fromJson(Map<String, dynamic> json) => Users( id: json["id"] ?? 0, name: json["name"] ?? "", username: json["username"] ?? "", email: json["email"] ?? "", address: Address.fromJson(json["address"] ?? {}), phone: json["phone"] ?? "", website: json["website"] ?? "", company: Company.fromJson(json["company"] ?? {}), );
3. 额外检查项
- 确保Android项目的
AndroidManifest.xml中添加了网络权限:<uses-permission android:name="android.permission.INTERNET"/> - iOS项目无需额外配置(接口为HTTPS,符合App Transport Security要求)
内容的提问来源于stack exchange,提问作者MS Droid
相关产品推荐
相关产品推荐

