Flutter 自定义ServiceModel解析接口后FutureBuilder的snapshot返回空问题
问题原因
- 未捕获请求和解析过程的异常:
getServiceDetail方法没有异常捕获逻辑,JSON解析抛出错误后Future进入失败状态,你当前的FutureBuilder仅判断了hasData,没有处理错误和加载状态的优先级,导致页面一直停留在加载视图。 - 缺少依赖的模型类定义:你仅实现了
ServiceModel和Data类,解析时依赖的ServiceIfo、PayInfo、以及嵌套的specialDescription对应模型均未定义,调用未声明类的fromJson方法会直接抛出异常,中断后续代码执行,所以print("Model is : $model")不会有输出。 - 潜在的字段不匹配问题:接口返回的JSON存在拼写错误的字段(如
custoemrPhoneNumber、serviceCategoryFeaturs),如果你的模型类字段拼写和返回字段不一致,也会触发解析异常。 - http调用参数不规范:高版本的
http包要求get方法传入Uri类型的地址,直接传字符串会触发参数异常。
解决方案
1. 给请求方法增加异常捕获,规范参数
Future<ServiceModel?> getServiceDetail() async { try { final url = "${MyStrings.baseUrl}api/providers/profile/ServiceAPI"; final _pref = await SharedPreferences.getInstance(); final token = _pref.getString('token'); if (token == null) throw Exception("登录状态失效,请重新登录"); final header = {'token': token}; // 转换为Uri类型,兼容高版本http包 final requestUri = Uri.parse(url + '?serviceId=59'); final response = await http.get(requestUri, headers: header); if (response.statusCode != 200) throw Exception("请求失败,状态码:${response.statusCode}"); final jsonData = json.decode(response.body); final model = ServiceModel.fromJson(jsonData); print("Model is : $model"); return model; } catch (e, stack) { print("请求/解析错误:$e"); print("错误堆栈:$stack"); return null; } }
2. 补全所有依赖的模型类
注意字段名要和接口返回的完全一致,包括拼写错误的字段也需要对应:
// 已有的ServiceModel、Data类保留,新增以下类 class ServiceIfo { int serviceId; int customerId; int providerId; List<dynamic> parentTitle; String title; double price; String date; String time; String address; List<SpecialDescription> specialDescription; String description; double lat; double lng; String customerFullName; // 和接口返回的拼写错误保持一致 String custoemrPhoneNumber; String serviceStatus; String endTime; String endDate; dynamic serviceCategoryFeaturs; ServiceIfo({ required this.serviceId, required this.customerId, required this.providerId, required this.parentTitle, required this.title, required this.price, required this.date, required this.time, required this.address, required this.specialDescription, required this.description, required this.lat, required this.lng, required this.customerFullName, required this.custoemrPhoneNumber, required this.serviceStatus, required this.endTime, required this.endDate, required this.serviceCategoryFeaturs, }); factory ServiceIfo.fromJson(Map<String, dynamic> json) => ServiceIfo( serviceId: json["serviceId"], customerId: json["customerId"], providerId: json["providerId"], parentTitle: List<dynamic>.from(json["parentTitle"].map((x) => x)), title: json["title"], // 兼容int类型的数值返回,统一转double price: json["price"]?.toDouble(), date: json["date"], time: json["time"], address: json["address"], specialDescription: List<SpecialDescription>.from(json["specialDescription"].map((x) => SpecialDescription.fromJson(x))), description: json["description"], lat: json["lat"]?.toDouble(), lng: json["lng"]?.toDouble(), customerFullName: json["customerFullName"], custoemrPhoneNumber: json["custoemrPhoneNumber"], serviceStatus: json["serviceStatus"], endTime: json["endTime"], endDate: json["endDate"], serviceCategoryFeaturs: json["serviceCategoryFeaturs"], ); Map<String, dynamic> toJson() => { "serviceId": serviceId, "customerId": customerId, "providerId": providerId, "parentTitle": List<dynamic>.from(parentTitle.map((x) => x)), "title": title, "price": price, "date": date, "time": time, "address": address, "specialDescription": List<dynamic>.from(specialDescription.map((x) => x.toJson())), "description": description, "lat": lat, "lng": lng, "customerFullName": customerFullName, "custoemrPhoneNumber": custoemrPhoneNumber, "serviceStatus": serviceStatus, "endTime": endTime, "endDate": endDate, "serviceCategoryFeaturs": serviceCategoryFeaturs, }; } class SpecialDescription { String question; int featureType; String choice; String answer; SpecialDescription({ required this.question, required this.featureType, required this.choice, required this.answer, }); factory SpecialDescription.fromJson(Map<String, dynamic> json) => SpecialDescription( question: json["question"], featureType: json["featureType"], choice: json["choice"], answer: json["answer"], ); Map<String, dynamic> toJson() => { "question": question, "featureType": featureType, "choice": choice, "answer": answer, }; } class PayInfo { bool isPaied; double paymentAmount; PayInfo({ required this.isPaied, required this.paymentAmount, }); factory PayInfo.fromJson(Map<String, dynamic> json) => PayInfo( isPaied: json["isPaied"], paymentAmount: json["paymentAmount"]?.toDouble(), ); Map<String, dynamic> toJson() => { "isPaied": isPaied, "paymentAmount": paymentAmount, }; }
3. 优化FutureBuilder逻辑,补全状态处理
FutureBuilder<ServiceModel?>( future: _service.getServiceDetail(), builder: (context, snapshot) { // 优先处理加载状态 if (snapshot.connectionState == ConnectionState.waiting) { return const Center( child: LinearProgressIndicator(color: Colors.red), ); } // 处理错误状态 if (snapshot.hasError) { return Center( child: Text("加载失败:${snapshot.error}"), ); } // 处理空数据 if (!snapshot.hasData || snapshot.data == null) { return const Center(child: Text("暂无服务数据")); } // 加载成功 return AnimatedSwitcher( duration: const Duration(seconds: 1), child: DetailedServicePager(data: snapshot.data!) ); }, )
内容的提问来源于stack exchange,提问作者David Black
相关产品推荐
相关产品推荐

