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

Flutter解析后端JSON用户资料数据时获取Null值如何解决

问题根因

解析后全为Null是多个代码逻辑错误共同导致的,核心问题点如下:

  • _loadProfileModel返回值类型不匹配:方法声明返回Future<ProfileModel>,实际返回的是原始接口响应的Map类型数据,FutureBuilder拿到的snapshot.data根本不是解析后的模型实例,类型不匹配无法取值。
  • JSON解析层级错误:日志能打印出完整返回值但解析为null,通常是漏取接口返回的嵌套data字段,或是后端返回的字段名和模型定义的字段名不一致(比如后端返回first_name、firstName,模型写firstname,json_serializable默认严格匹配键名,匹配不到就返回null)。
  • 变量作用域错误:无论是旧版代码还是简化版代码,都在setState方法内部声明了ProfileModel profileModel = ...局部变量,这个局部变量和State类的全局profileModel属性完全无关,全局实例始终是初始化的空模型,所有字段默认都是null。
  • FutureBuilder状态逻辑写反:原代码中ConnectionState.waiting(加载中状态)返回Error组件,其余状态返回加载指示器,逻辑完全颠倒,加载阶段直接抛错。
  • 重复触发网络请求:直接把_loadProfileModel()写在FutureBuilder的future参数中,每次页面重绘都会重新发起请求,无谓消耗性能还会导致状态错乱。
修复步骤
  • 先确认接口返回结构:打印/profile/getData接口的完整响应,确认个人资料字段是直接挂在响应根节点,还是在data嵌套字段下;如果后端字段名和模型字段名不一致,给对应字段加@JsonKey(name: "后端实际字段名")注解,例如:
@JsonKey(name: "firstName")
String? firstname;
  • 修正变量作用域:给全局profileModel赋值时,不要在变量前加类型声明,避免创建同名局部变量覆盖全局属性。
  • 修正Future返回值:_loadProfileModel必须返回解析完成的ProfileModel实例,不能返回原始响应Map。
  • 调整FutureBuilder状态判断逻辑,对应好加载、错误、成功三种状态的组件返回。
  • 提前在initState中缓存请求Future对象,不要直接在FutureBuilder内调用请求方法,避免build触发重复请求。
  • 修改完模型类或JsonKey注解后,重新执行序列化生成命令:flutter pub run build_runner build --delete-conflicting-outputs,确保生成的profile_model.g.dart是最新版本。
修复后可直接复用的代码
class _SettingsProfileState extends State<SettingsProfile> {
  final _formKey = GlobalKey<FormState>();
  final networkHandler = NetworkHandler();
  ProfileModel? profileModel;
  // 缓存future避免重复请求
  late Future<ProfileModel> profileFuture;
  bool hasProfile = false;

  TextEditingController firstnameController = TextEditingController();
  TextEditingController lastnameController = TextEditingController();
  TextEditingController birthdayController = TextEditingController();
  TextEditingController weightController = TextEditingController();

  @override
  void initState() {
    super.initState();
    checkProfile();
  }

  void checkProfile() async {
    var response = await networkHandler.get('/profile/checkProfile');
    hasProfile = response['status'] == true;
    if (hasProfile) {
      profileFuture = _loadProfileModel();
    }
    setState(() {});
  }

  Future<ProfileModel> _loadProfileModel() async {
    var response = await networkHandler.get("/profile/getData");
    // 根据实际接口结构调整:如果字段嵌套在data下就取response["data"],否则直接传response
    final Map<String, dynamic> profileData = response["data"];
    return ProfileModel.fromJson(profileData);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Mon profil')),
      body: hasProfile ? showProfile() : emptyProfile(),
    );
  }

  Widget showProfile() {
    return FutureBuilder<ProfileModel>(
      future: profileFuture,
      builder: (BuildContext context, AsyncSnapshot<ProfileModel> snapshot) {
        // 加载状态
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Center(child: CircularProgressIndicator());
        }
        // 请求错误
        if (snapshot.hasError) {
          return Center(child: Text('加载失败:${snapshot.error}'));
        }
        // 加载成功
        if (snapshot.hasData) {
          profileModel = snapshot.data;
          return Card(
            elevation: 5,
            margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
            child: Container(
              padding: const EdgeInsets.all(8),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Expanded(
                      child: Container(
                        padding: const EdgeInsets.only(bottom: 8),
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Padding(
                              padding: const EdgeInsets.only(left: 8, right: 8),
                              child: Text(
                                profileModel?.firstname ?? '',
                                style: const TextStyle(
                                    fontSize: 16,
                                    fontWeight: FontWeight.bold),
                              ),
                            ),
                            Padding(
                              padding: const EdgeInsets.only(left: 8, right: 8),
                              child: Text(profileModel?.lastname ?? ''),
                            ),
                            Padding(
                              padding: const EdgeInsets.only(left: 8, right: 8),
                              child: Text(profileModel?.weight ?? ''),
                            )
                          ],
                        ),
                      ))
                ],
              ),
            ),
          );
        }
        return const Center(child: Text('暂无数据'));
      },
    );
  }

  Widget emptyProfile() {
    // 原有未填写资料页逻辑
    return const Center(child: Text('请先完善个人资料'));
  }
}

内容的提问来源于stack exchange,提问作者flutterby

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 04:57:07