Flutter调用Beeceptor接口时遇类型转换异常求助
解决Dart中"null is not a subtype of String of type cast"类型转换异常
问题描述
使用Beeceptor创建Web服务后,调用接口更新UI时抛出**"null is not a subtype of String of type cast"**类型转换异常,无法正常加载数据。
API返回数据格式
当前Beeceptor返回的JSON结构如下:
[ { "0":{ "name":"Emmanuel Armoo", "imageUrl":"https://www.pexels.com/photo/man-smiling-behind-wall-220453/", "time":"2:00", "description":"The is an ancient geek priest who discovered the whole fact to unlease the new technological advancement" }, "1":{ "name":"Emmanuel Armoo", "imageUrl":"https://www.pexels.com/photo/man-smiling-behind-wall-220453/", "time":"2:00", "description":"The is an ancient geek priest who discovered the whole fact to unlease the new technological advancement" }, "3":{ "name":"Sister Armoo", "imageUrl":"https://www.pexels.com/photo/man-smiling-behind-wall-220453/", "time":"2:00", "description":"The is an ancient geek priest who discovered the whole fact to unlease the new technological advancement" }, "4":{ "name":"Kofi Armoo", "imageUrl":"https://www.pexels.com/photo/man-smiling-behind-wall-220453/", "time":"2:00", "description":"The is an ancient geek priest who discovered the whole fact to unlease the new technological advancement" } } ]
相关代码
User类代码
import 'package:my_api_practice/Endpoint/endpoint.dart'; import 'dart:convert'; import 'package:http/http.dart'as http; import 'UserDetails.dart'; import ''; part 'User.g.dart'; class User{ String? name; String? imageUrl; String? time; List<UserDetails>?details; User({required this.details,required this.name,required this.imageUrl,required this.time}); factory User.fromJson(Map<String,dynamic>json)=>_$UserFromJson(json); User.blank() :name='', imageUrl='', time='', details=[]; static Future <List<User>>firstApi()async{ http.Response response=await http.get(Uri.parse("https://xcompany.free.beeceptor.com/api/v1/users")); List<User>jsonitem=[]; if(response.statusCode!=200){ print(response.body); } for(var newItems in json.decode(response.body)){ jsonitem.add(User.fromJson(newItems)); } return jsonitem; } }
UI代码
import 'package:my_api_practice/models/User.dart'; import 'package:flutter/material.dart'; class UserList extends StatefulWidget{ createState()=>_UserList(); } class _UserList extends State<UserList> { bool isWaiting = false; List<User>users = []; void initState(){ super.initState(); ApiData(); } ApiData() async { isWaiting=true; var jsonItem = await User.firstApi(); setState(() { users = jsonItem; isWaiting=false; }); } Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('UserList'), ), body: Column( children: [ isWaiting ? LinearProgressIndicator( value: null, backgroundColor: Colors.grey, valueColor: AlwaysStoppedAnimation<Color>(Colors.black), ) : Container( child:Text('No UI to load') ), Expanded( child: ListView.builder( itemCount: users.length, itemBuilder: _itemTiles,) ) ], ), ); } Widget _itemTiles(BuildContext context, int index) { return ListTile( leading: _listImages(context, this.users[index]), title: _listTitles(context, this.users[index]), trailing: _listTimes(context, this.users[index]), ); } Widget _listImages(BuildContext context, User user) { return ClipRRect( borderRadius: BorderRadius.all(Radius.circular(30)), child: Image.network(user.imageUrl!) ); } Widget _listTitles(BuildContext context, User user) { return Text(user.name!); } Widget _listTimes(BuildContext context, User user) { return Text(user.time!); } }
问题分析
- API结构与代码预期不匹配:代码期望返回
User对象的数组,但实际API返回的是包含单个对象的数组,该对象以索引字符串("0"、"1"等)为键,值才是用户数据。直接遍历外层数组会把整个索引对象当成User的JSON解析,导致字段不匹配。 - User类字段与API返回不一致:User类定义了
details字段,但API返回中没有该字段,反而存在description字段,序列化时会因找不到对应字段触发null类型转换错误。 - 空安全处理不当:UI代码中直接用
!强制解包nullable字段,若API返回字段为null会触发异常。
解决方案
方案1:修正API返回格式(推荐)
修改Beeceptor的响应,直接返回User对象的数组,格式如下:
[ { "name":"Emmanuel Armoo", "imageUrl":"https://www.pexels.com/photo/man-smiling-behind-wall-220453/", "time":"2:00", "description":"xxx" }, { "name":"Sister Armoo", "imageUrl":"https://www.pexels.com/photo/man-smiling-behind-wall-220453/", "time":"2:00", "description":"xxx" } ]
方案2:适配现有API格式修改代码
如果无法修改API格式,调整解析逻辑和User类:
- 修改
firstApi方法的解析逻辑:
static Future<List<User>> firstApi()async{ http.Response response=await http.get(Uri.parse("https://xcompany.free.beeceptor.com/api/v1/users")); List<User> jsonitem=[]; if(response.statusCode!=200){ print(response.body); } // 解析外层数组,取出包含用户的对象 var outerArray = json.decode(response.body) as List; if(outerArray.isNotEmpty){ var userMap = outerArray[0] as Map<String, dynamic>; // 遍历对象的values获取每个用户数据 for(var newItems in userMap.values){ jsonitem.add(User.fromJson(newItems)); } } return jsonitem; }
- 修正User类字段:
class User{ String? name; String? imageUrl; String? time; String? description; // 替换details为API返回的description字段 // 调整构造函数参数 User({required this.description, required this.name, required this.imageUrl, required this.time}); factory User.fromJson(Map<String,dynamic>json)=>_$UserFromJson(json); User.blank() :name='', imageUrl='', time='', description=''; // 同步修改空白构造函数 }
修改后重新运行flutter pub run build_runner build生成新的序列化代码。
- 优化UI的空安全处理:
Widget _listImages(BuildContext context, User user) { return ClipRRect( borderRadius: BorderRadius.all(Radius.circular(30)), child: Image.network(user.imageUrl ?? 'https://默认图片地址') ); } Widget _listTitles(BuildContext context, User user) { return Text(user.name ?? '未知名称'); } Widget _listTimes(BuildContext context, User user) { return Text(user.time ?? '未知时间'); }
内容的提问来源于stack exchange,提问作者Emmanuel Armoo
相关产品推荐
相关产品推荐

