Flutter解析JSON显示餐厅列表时String?类型不匹配错误如何解决
问题修复方案
一、模型类构造函数相关错误修复
错误原因
- Dart空安全规则限制:声明为非空的
final字段必须在构造函数中明确赋值,要么添加required修饰参数,要么将字段标记为可空(类型后加?) Map泛型写法错误:代码中Map<"String", dynamic>的String多了引号,正确应为Map<String, dynamic>- JSON解析未做类型兼容处理:比如接口返回的
rating可能是int类型,直接赋值给double类型会报错,同时未做字段空判断
修正后模型代码
import 'dart:convert'; class RestaurantDetail { final Restaurant? restaurants; RestaurantDetail({this.restaurants}); factory RestaurantDetail.fromJson(Map<String, dynamic> json) { return RestaurantDetail( restaurants: json['restaurants'] != null ? Restaurant.fromJson(json['restaurants']) : null, ); } } class Restaurant { final String? id; final String? name; final String? description; final String? pictureId; final String? city; final double? rating; final Menus? menus; Restaurant({ this.id, this.name, this.description, this.pictureId, this.city, this.rating, this.menus, }); factory Restaurant.fromJson(Map<String, dynamic> json) { return Restaurant( id: json['id']?.toString(), name: json['name']?.toString(), description: json['description']?.toString(), pictureId: json['pictureId']?.toString(), city: json['city']?.toString(), rating: json['rating'] is int ? (json['rating'] as int).toDouble() : json['rating']?.toDouble(), menus: json['menus'] != null ? Menus.fromJson(json['menus']) : null, ); } } class Menus { final Foods? foods; final Drinks? drinks; Menus({ this.foods, this.drinks, }); factory Menus.fromJson(Map<String, dynamic> json) { return Menus( foods: json['foods'] != null ? Foods.fromJson(json['foods']) : null, drinks: json['drinks'] != null ? Drinks.fromJson(json['drinks']) : null); } } class Foods { final String? name; Foods({this.name}); factory Foods.fromJson(Map<String, dynamic> json) { return Foods( name: json['name']?.toString(), ); } } class Drinks { final String? name; Drinks({this.name}); factory Drinks.fromJson(Map<String, dynamic> json) { return Drinks( name: json['name']?.toString(), ); } } List<RestaurantDetail> parseRestaurant(String? json) { if (json == null) { return []; } try { final List parsed = jsonDecode(json); return parsed.map((json) => RestaurantDetail.fromJson(json)).toList(); } catch (e) { return []; } }
二、首页snapshot.data类型不匹配错误修复
错误原因
FutureBuilder的异步请求返回结果是可空类型String?,而原parseRestaurant函数要求传入不可空的String类型,同时没有处理加载中、加载失败的状态直接调用数据会导致异常。
修正后首页代码
import 'package:flutter/material.dart'; import 'package:restaurant/data/restaurant.dart'; import 'package:restaurant/style/theme.dart'; class HomePage extends StatelessWidget { static const routeName = '/article_list'; const HomePage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: kBackgroundColor, body: FutureBuilder<String>( future: DefaultAssetBundle.of(context) .loadString('assets/local_restaurant.json'), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } if (snapshot.hasError) { return Center(child: Text('加载失败:${snapshot.error}')); } final List<RestaurantDetail> restaurants = parseRestaurant(snapshot.data); return ListView.builder( itemCount: restaurants.length, itemBuilder: (context, index) { return _buildRestaurantItem(context, restaurants[index]); }, ); }, ), ); } Widget _buildRestaurantItem( BuildContext context, RestaurantDetail restaurantDetail) { final restaurant = restaurantDetail.restaurants; if (restaurant == null) return const SizedBox.shrink(); return ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), leading: Image.network( restaurant.pictureId ?? '', width: 100, errorBuilder: (context, error, stackTrace) => const Icon(Icons.broken_image, size: 100), ), title: Text(restaurant.name ?? '未知餐厅'), subtitle: Text(restaurant.city ?? '未知城市'), onTap: () {}, ); } }
内容的提问来源于stack exchange,提问作者muhammad alam nur haris
相关产品推荐
相关产品推荐

