Flutter如何将token、userId存入SharedPreferences并在其他页面读取使用
解决方案
1 修复userId存储失败问题
你当前存储失败的核心原因有两个:一是接口返回的userId可能为字符串类型,直接调用setInt会触发类型异常导致存储终止;二是Album类的fromJson方法字段映射完全不匹配接口返回结构,会触发解析异常。
修改登录接口请求的存储逻辑:
Future<Album> createAlbum(String employee_custom_id, String password) async { SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); final response = await http.post( Uri.parse('https://你的实际域名.com/api/auth/login'), headers: <String, String>{ 'Content-Type': 'application/json', }, body: jsonEncode(<String, String>{ 'employee_custom_id': employee_custom_id, 'password': password, }), ); final data = json.decode(response.body); if (response.statusCode == 200) { // 存储token sharedPreferences.setString("token", data['token']); // 统一转成int类型再存储,避免接口返回字符串类型导致存储失败 int userId = int.parse(data['userId'].toString()); sharedPreferences.setInt("userId", userId); // 强制提交持久化(iOS端建议添加,安卓默认自动提交) await sharedPreferences.commit(); log('存储成功:token=${data['token']}, userId=$userId'); return Album.fromJson(data); } else { throw Exception('登录请求失败'); } }
同步修复Album类的字段映射:
class Album { final String token; final int userId; final String message; final String passwordChanged; Album({ required this.token, required this.userId, required this.message, required this.passwordChanged, }); factory Album.fromJson(Map<String, dynamic> json) { return Album( token: json['token'], userId: json['userId'], message: json['message'], passwordChanged: json['passwordChanged'], ); } }
2 登录页实现userId逻辑判断+Snackbar提示
修改登录按钮的onPressed逻辑,监听登录结果做对应提示:
onPressed: () { if(_emailController.text.isEmpty || _passwordController.text.isEmpty){ ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('账号或密码不能为空')) ); return; } setState(() { _futureAlbum = createAlbum(_emailController.text, _passwordController.text); }); // 异步监听登录结果 _futureAlbum?.then((album) { // 登录成功,用userId做判断逻辑 if(album.userId > 0){ ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('登录成功,欢迎用户${album.userId}')) ); // 跳转列表页 Navigator.push(context, MaterialPageRoute(builder: (context)=> const ListsPage())); }else{ ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('账号异常,请联系管理员')) ); } }).catchError((e){ ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('登录失败:${e.toString()}')) ); }); },
3 lists.dart页面读取存储的token和userId
只需要先初始化SharedPreferences实例,再通过key取值即可:
Future<List<ListAlbum>> listData() async { // 先获取SharedPreferences实例 SharedPreferences sp = await SharedPreferences.getInstance(); // 取值,空值返回null便于判断登录状态 final String? token = sp.getString("token"); final int? userId = sp.getInt("userId"); // 未登录状态抛出异常后续自行处理 if(token == null || userId == null){ throw Exception('用户未登录,请先登录'); } String url = 'https://你的实际域名.com/api/getOrganizationData?token=${token}'; Dio dio = Dio(); dio.options.headers['Content-Type'] = 'application/json'; // 接口需要传userId的话直接使用上面取到的userId变量即可 final body = {'limit': 100, 'orderBy': 'idEmployee', 'orderType': 'DESC'}; final response = await dio.post(url, data: body); if (response.statusCode == 200) { print(response.statusCode); print(response.data); return response.data["data"]["data"] .map<ListAlbum>((json) => ListAlbum.fromJson(json)) .toList(); } else { throw Exception('请求数据失败'); } }
其他页面通用读取方式
任何需要使用token、userId的页面,都可以用如下方式直接读取:
SharedPreferences sp = await SharedPreferences.getInstance(); String? token = sp.getString("token"); int? userId = sp.getInt("userId");
退出登录时清除存储数据:
SharedPreferences sp = await SharedPreferences.getInstance(); sp.remove("token"); sp.remove("userId"); // 或直接清空所有存储 sp.clear();
内容的提问来源于stack exchange,提问作者Fozuda
相关产品推荐
相关产品推荐

