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

Flutter中使用Dio与SharedPreference遇非空参数错误,API响应正常却无法跳转页面求助

解决SharedPreferences空指针与页面导航失效问题

看起来你遇到的Invalid argument(s) (value): Must not be null错误,以及登录后进入catch块、导航失效的问题,根源在于两个关键问题:SharedPreferences未初始化,以及异步代码写法混乱导致错误捕获不全面。咱们一步步来修复:

核心问题分析

  1. SharedPreferences未初始化:你只是声明了SharedPreferences myPrefs;,但从未通过SharedPreferences.getInstance()获取实例,导致myPrefs是null,调用setString/setInt时直接触发空指针异常,这就是错误提示的来源。
  2. 混合使用async/await与.then()嵌套:这种写法会让错误捕获逻辑失效——内层.then()里的错误要么被自己的catchError吃掉,要么无法被外层的try-catch捕获,最终导致程序进入外层catch块,跳过了导航代码。

修复步骤与代码调整

1. 先初始化SharedPreferences实例

在使用任何SharedPreferences的方法前,必须先调用SharedPreferences.getInstance()获取实例,这是异步操作,要用await等待完成。

2. 统一用async/await代替.then()嵌套

把所有的.then()替换成await,让代码逻辑更清晰,同时所有异步操作的错误都能被外层的try-catch统一捕获。

修正后的登录函数代码

SharedPreferences myPrefs;
Future login() async {
  Dio dio = Dio();
  try {
    // 第一步:初始化SharedPreferences
    myPrefs = await SharedPreferences.getInstance();
    
    final loginData = {
      'username': "Munib khatri",
      'password': "Munib123",
      'date': formattedDate
    };
    
    // 登录API调用,用await代替then
    final loginResponse = await dio.post(
      localhostUrlLogin,
      data: json.encode(loginData),
    );
    print('登录响应数据: ${loginResponse.data}');
    
    // 提取登录返回的用户信息
    String name = loginResponse.data['User']['username'];
    String email = loginResponse.data['User']['email'];
    String designation = loginResponse.data['User']['Designation'];
    String token = loginResponse.data['AccessToken'];
    
    // 调用休假统计API,同样用await
    final leaveData = {
      "token": token, 
      "username": name, 
      "leave": "Approved", 
      "type": "maternity"
    };
    final leaveResponse = await dio.post(
      localHostUrlleaveCount,
      data: json.encode(leaveData),
    );
    
    int sickCount = leaveResponse.data['sick'];
    int annualCount = leaveResponse.data['annual'];
    
    // 存储数据到SharedPreferences
    await myPrefs.setInt('sickCount', sickCount);
    await myPrefs.setInt('annualCount', annualCount);
    await myPrefs.setString('name', name);
    await myPrefs.setString('email', email);
    await myPrefs.setString('designation', designation);
    
    // 导航到目标页面,这一步现在只会在所有操作成功后执行
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => Navigation()),
    );
    
  } catch (e) {
    print('错误详情: ${e.toString()}');
    // 这里可以添加错误提示给用户,比如SnackBar
  }
}

额外优化:在EmployeeNavigation中正确获取SharedPreferences数据

你现在的EmployeeNavigation里的全局变量获取数据的方式不太合理,建议在initState中异步获取,避免build方法重复执行:

class EmployeeNavigationState extends State<EmployeeNavigation> {
  int _selectedTab = 0;
  final _pageOptions = [Home(), location(), Profile()];
  String getname = "";
  String getemail = "";
  String getdesignation = "";

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

  Future<void> _loadSavedUserData() async {
    final prefs = await SharedPreferences.getInstance();
    setState(() {
      // 使用??操作符处理null情况,避免空值
      getname = prefs.getString('name') ?? '未获取到姓名';
      getemail = prefs.getString('email') ?? '未获取到邮箱';
      getdesignation = prefs.getString('designation') ?? '未获取到职位';
    });
  }

  // 其余build方法代码保持不变
}

为什么之前的代码会失效?

  • 未初始化SharedPreferences是直接触发错误的原因,null对象调用方法必然抛出异常;
  • .then()嵌套的写法让错误捕获范围混乱,内层的空指针异常无法被外层try-catch捕获,反而被then的回调逻辑触发后,直接进入外层catch块,跳过了导航代码;
  • 用await统一处理异步操作后,所有步骤都会按顺序执行,任何一步出错都会进入catch块,成功的话才会执行导航。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 09:07:27