Flutter中使用Dio与SharedPreference遇非空参数错误,API响应正常却无法跳转页面求助
看起来你遇到的Invalid argument(s) (value): Must not be null错误,以及登录后进入catch块、导航失效的问题,根源在于两个关键问题:SharedPreferences未初始化,以及异步代码写法混乱导致错误捕获不全面。咱们一步步来修复:
核心问题分析
- SharedPreferences未初始化:你只是声明了
SharedPreferences myPrefs;,但从未通过SharedPreferences.getInstance()获取实例,导致myPrefs是null,调用setString/setInt时直接触发空指针异常,这就是错误提示的来源。 - 混合使用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
相关产品推荐
相关产品推荐

