You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter FutureBuilder持续加载且出现int转double类型转换错误

Flutter FutureBuilder持续加载且出现int转double类型转换错误

看起来你碰到了两个关联的问题:FutureBuilder一直卡在加载状态,同时控制台抛出type 'int' is not a subtype of type 'double'的类型转换错误。我来一步步帮你分析和解决:

一、先解决FutureBuilder持续加载的问题

你当前的FutureBuilder代码里,future: AllProductService().getAllProducts()是直接在build方法中创建的Future实例。这会导致每次Widget重建(比如屏幕旋转、父组件状态变化)时,都会重新发起一次全新的网络请求,FutureBuilder会一直等待新的Future完成,从而看起来“永远在加载”。

解决方案:把Future实例存在State变量中,只初始化一次

修改你的home_page.dart代码,将Future的创建移到initState里:

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // 用late延迟初始化,只在组件初始化时赋值一次
  late final Future<List<ProductModel>> _productsFuture;

  @override
  void initState() {
    super.initState();
    // 仅在组件第一次创建时发起请求
    _productsFuture = AllProductService().getAllProducts();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FutureBuilder<List<ProductModel>>(
        // 使用存储好的Future实例,避免重复发起请求
        future: _productsFuture,
        builder: (context, snapshot) {
          if (snapshot.connectionState != ConnectionState.done) {
            return const Center(child: CircularProgressIndicator.adaptive());
          } else if (snapshot.hasError) {
            return Center(child: Text('加载出错: ${snapshot.error}'));
          }
          final products = snapshot.data!;
          return GridView.builder(
            itemCount: products.length,
            gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 2,
              childAspectRatio: 1.6,
            ),
            itemBuilder: (_, i) => Text(products[i].title),
          );
        },
      ),
    );
  }
}

二、解决int转double的类型转换错误

虽然你在fromJson方法里已经用了(json['price'] as num).toDouble()这类处理,但还是报错,大概率是下面两个原因之一:

1. Api类的get方法没有正确解析JSON响应

检查你的Api类实现,确保它正确调用了jsonDecode解析响应体。如果Api.get()返回的是原始字符串(response.body)而不是解析后的JSON对象/数组,那么res as List<dynamic>会抛出类型错误,进而引发后续的转换异常。

正确的Api类get方法示例:

import 'package:http/http.dart' as http;
import 'dart:convert';

class Api {
  Future<dynamic> get({required String url}) async {
    final response = await http.get(Uri.parse(url));
    if (response.statusCode == 200) {
      // 关键:解析JSON响应为动态类型(这里返回List或Map)
      return jsonDecode(response.body);
    } else {
      throw Exception('请求失败,状态码: ${response.statusCode}');
    }
  }
}

2. 给JSON解析添加安全防护

为了避免意外的空值或类型不匹配,建议在fromJson方法中加入空值检查和默认值,这样即使某个字段异常,也不会直接崩溃:

// 修改ProductModel.fromJson
factory ProductModel.fromJson(Map<String, dynamic> json) {
  return ProductModel(
    id: (json['id'] as num?)?.toInt() ?? 0,
    title: json['title'] as String? ?? '无标题',
    price: (json['price'] as num?)?.toDouble() ?? 0.0,
    description: json['description'] as String? ?? '无描述',
    image: json['image'] as String? ?? '',
    rating: (json['rating'] as Map<String, dynamic>?) != null
        ? RatingModel.fromJson(json['rating'] as Map<String, dynamic>)
        : RatingModel(rate: 0.0, count: 0),
  );
}

// 修改RatingModel.fromJson
factory RatingModel.fromJson(Map<String, dynamic> json) {
  return RatingModel(
    rate: (json['rate'] as num?)?.toDouble() ?? 0.0,
    count: (json['count'] as num?)?.toInt() ?? 0,
  );
}

三、调试验证

可以在getAllProducts方法中添加打印语句,确认数据是否正确解析:

Future<List<ProductModel>> getAllProducts() async {
  final res = await Api().get(
    url: 'https://fakestoreapi.com/products',
  );
  print('解析后的原始数据: $res');
  print('数据长度: ${(res as List).length}');
  final List<dynamic> data = res as List<dynamic>;
  return data
      .map((e) => ProductModel.fromJson(e as Map<String, dynamic>))
      .toList();
}

这样能直观看到解析后的数据结构是否符合预期。

总结一下:先修复Future重复创建的问题,再确保JSON解析逻辑正确,最后给解析加一层安全防护,你的产品列表应该就能正常显示了。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 09:53:08