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

Flutter中解决类型不匹配及年龄计算duration为null的问题

问题修复方案

1. 解决类型不匹配错误

SharedPreferences只能存储字符串类型,你直接把读取到的String?赋值给DateTime?变量,必然会触发类型不兼容的报错。正确的做法是先取出字符串,再通过DateTime.parse()转换为DateTime对象,同时要处理空值和解析失败的情况:

// 错误写法
// DateTime? birthday = prefs.getString('birthday');

// 正确写法
final prefs = await SharedPreferences.getInstance();
String? birthdayStr = prefs.getString('birthday');
DateTime? birthday;

if (birthdayStr != null) {
  try {
    birthday = DateTime.parse(birthdayStr);
  } catch (e) {
    // 处理无效日期字符串的情况,比如打印日志
    print('日期解析失败: $e');
  }
}

2. 修复duration为null的问题

你得到的duration为null,大概率是因为birthday变量为空(要么没存储过数据,要么解析失败)。另外要注意:Duration本身没有直接获取年份的属性,不能直接用它计算年龄,得手动处理年份差和生日是否过了当年的判断。

年龄计算逻辑示例

int? calculateAge(DateTime? birthday) {
  if (birthday == null) return null;
  
  final now = DateTime.now();
  int age = now.year - birthday.year;
  
  // 如果当年生日还没到,年龄减1
  if (now.month < birthday.month || 
      (now.month == birthday.month && now.day < birthday.day)) {
    age--;
  }
  
  return age;
}

完整可运行示例代码

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

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

  @override
  State<BirthdayAgePage> createState() => _BirthdayAgePageState();
}

class _BirthdayAgePageState extends State<BirthdayAgePage> {
  DateTime? _savedBirthday;
  int? _currentAge;

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

  // 从SharedPreferences读取生日
  Future<void> _loadSavedBirthday() async {
    final prefs = await SharedPreferences.getInstance();
    String? birthdayStr = prefs.getString('user_birthday');
    
    if (birthdayStr != null) {
      try {
        setState(() {
          _savedBirthday = DateTime.parse(birthdayStr);
        });
        _currentAge = calculateAge(_savedBirthday);
      } catch (e) {
        print('解析生日失败: $e');
      }
    }
  }

  // 保存生日到SharedPreferences
  Future<void> _saveBirthday(DateTime pickedDate) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString('user_birthday', pickedDate.toIso8601String());
    setState(() {
      _savedBirthday = pickedDate;
      _currentAge = calculateAge(pickedDate);
    });
  }

  // 计算年龄
  int? calculateAge(DateTime? birthday) {
    if (birthday == null) return null;
    
    final now = DateTime.now();
    int age = now.year - birthday.year;
    
    if (now.month < birthday.month || 
        (now.month == birthday.month && now.day < birthday.day)) {
      age--;
    }
    
    return age;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('生日与年龄计算')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              _savedBirthday != null 
                  ? '已选生日: ${_savedBirthday!.year}-${_savedBirthday!.month}-${_savedBirthday!.day}'
                  : '未选择生日',
              style: const TextStyle(fontSize: 18),
            ),
            const SizedBox(height: 20),
            Text(
              _currentAge != null 
                  ? '当前年龄: $_currentAge岁'
                  : '无法计算年龄',
              style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 30),
            ElevatedButton(
              onPressed: () async {
                final pickedDate = await showDatePicker(
                  context: context,
                  initialDate: DateTime.now(),
                  firstDate: DateTime(1900),
                  lastDate: DateTime.now(),
                );

                if (pickedDate != null) {
                  await _saveBirthday(pickedDate);
                }
              },
              child: const Text('选择生日'),
            ),
          ],
        ),
      ),
    );
  }
}

关键注意事项

  • 存储生日时用toIso8601String(),这是DateTime的标准字符串格式,解析时不会出错。
  • 解析字符串必须加try-catch,避免无效字符串导致崩溃。
  • 计算年龄要判断当年生日是否已过,否则会出现提前算一岁的错误。
  • SharedPreferences的操作都是异步的,必须用async/await处理,不能同步调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 01:45:34