Flutter升级后调用snapshot.data的length、map方法报错如何解决
问题原因
你遇到的报错是Flutter升级到空安全版本后,类型校验更严格 + 代码逻辑错误共同导致的,核心问题有3个:
- FutureBuilder传参错误:你在
initState已经调用了fetchData(widget.medicineCatUniqId),但build方法里FutureBuilder的future参数又传了fetchData(medicineSubCategoryApi),初始状态下medicineSubCategoryApi是null,相当于请求参数错误,接口自然返回不了有效数据。而且future直接写方法调用的话,每次页面重绘都会重复发起请求,属于严重的逻辑错误。 - 类型不匹配:旧版Flutter没有强空安全校验,
snapshot.data默认是dynamic类型可以任意调用方法,升级后FutureBuilder没有指定泛型,snapshot.data会被推断为Object?类型,Object本身没有length和map方法,直接调用就会报错。 - 你贴的第二份测试代码存在语法错误:代码里残留了上一个版本的括号,语法不合法也会导致编译/运行报错。
修复方案
按如下步骤修改代码即可解决:
- 在State中定义专门的Future变量存储请求任务,避免重复发起请求
- 给FutureBuilder指定泛型,明确返回数据是List类型
- 调用方法前做类型校验和空判断
修改后可运行完整代码
class _TabPageState extends State<TabPage> { late Future<List> _fetchDataFuture; // 定义Future变量存储请求任务 @override void initState() { super.initState(); // 初始化时只发起一次请求,参数用widget传进来的medicineCatUniqId _fetchDataFuture = fetchData(widget.medicineCatUniqId); } Future<List> fetchData(var medicineCatUniqId) async { var api = Uri.parse('$baseUrl/productSubCatApi.php?a2rTokenKey=$a2rTokenKey&pcat=$medicineCatUniqId'); var response = await http.get(api); print("medicineCatApiLnk " + api.toString()); print("medicineCat" + response.body); List medicineSubCategoryApi = jsonDecode(response.body); print("medicineCatString" + medicineSubCategoryApi.toString()); return medicineSubCategoryApi; } @override Widget build(BuildContext context) { return MaterialApp( home: FutureBuilder<List>( future: _fetchDataFuture, // 直接传已经创建好的Future,不会重复请求 builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { if (snapshot.hasError) { return Text('Error: ${snapshot.error}'); } // 明确snapshot.data是List类型,直接调用方法不会报错 List data = snapshot.data!; print(data.length.toString()); print(data.toString()); return DefaultTabController( length: data.length, child: Scaffold( appBar: AppBar( title: const Text('Tabbed AppBar'), bottom: TabBar( isScrollable: true, tabs: data .map<Widget>((choice) => Tab( text: choice['psubCatName'], )) .toList(), ), ), body: TabBarView( physics: NeverScrollableScrollPhysics(), children: data.map<Widget>((choice) { return Padding( padding: const EdgeInsets.all(20.0), child: ChoicePage( choice: choice, ), ); }).toList(), ), ), ); } else { return const Text('Loading'); } }), ); } } class ChoicePage extends StatelessWidget { const ChoicePage({Key? key, this.choice}) : super(key: key); final Map choice; // 明确类型,避免空安全报错 @override Widget build(BuildContext context) { final TextStyle? textStyle = Theme.of(context).textTheme.headline4; return Card( color: Colors.white, child: Center( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Text( choice['psubCatName'], style: textStyle, ), ], ), ), ); } }
内容的提问来源于stack exchange,提问作者Deepak
相关产品推荐
相关产品推荐

