Flutter:如何在Provider中无StatefulWidget使用shared_preferences
一、处理异步特性(Futures)
不用StatefulWidget时,FutureBuilder是最直接的解决方案,它能自动监听Future的状态(等待、完成、错误),并根据状态渲染对应UI,完全不需要依赖setState。如果需要实时监听数据变化,也可以结合ValueNotifier来维护状态,但FutureBuilder更适合单次异步加载的场景。
二、数据序列化问题
shared_preferences仅支持存储基础数据类型:String、int、bool、double、List<String>。如果要存储自定义对象,必须手动将其序列化为JSON字符串(用jsonEncode),读取时再反序列化为对象(用jsonDecode)——该包本身没有内置复杂对象的序列化功能。
完整示例
下面是一个无状态Widget的示例,实现保存/读取用户偏好的用户名:
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'dart:convert'; // 自定义用户偏好模型(示例) class UserPrefs { final String username; UserPrefs({required this.username}); // 序列化为JSON字符串 String toJson() => jsonEncode({'username': username}); // 从JSON字符串反序列化 static UserPrefs? fromJson(String jsonString) { try { final map = jsonDecode(jsonString) as Map<String, dynamic>; return UserPrefs(username: map['username'] ?? ''); } catch (e) { return null; } } } class PrefsDemo extends StatelessWidget { final TextEditingController _usernameController = TextEditingController(); // 保存用户名到shared_preferences Future<void> _saveUsername(String username) async { final prefs = await SharedPreferences.getInstance(); final userPrefs = UserPrefs(username: username); await prefs.setString('user_prefs', userPrefs.toJson()); } // 从shared_preferences读取用户名 Future<UserPrefs?> _loadUsername() async { final prefs = await SharedPreferences.getInstance(); final jsonString = prefs.getString('user_prefs'); if (jsonString != null) { return UserPrefs.fromJson(jsonString); } return null; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('SharedPrefs无状态示例')), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ TextField( controller: _usernameController, decoration: const InputDecoration(labelText: '输入用户名'), ), const SizedBox(height: 16), ElevatedButton( onPressed: () => _saveUsername(_usernameController.text), child: const Text('保存'), ), const SizedBox(height: 24), // 用FutureBuilder处理异步加载 FutureBuilder<UserPrefs?>( future: _loadUsername(), initialData: null, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const CircularProgressIndicator(); } else if (snapshot.hasError) { return const Text('加载数据出错'); } else { final username = snapshot.data?.username ?? '未设置用户名'; return Text('当前保存的用户名:$username'); } }, ), ], ), ), ); } }
补充说明
- 如果需要实时监听跨页面的shared_preferences数据变化,可以用
ValueNotifier结合Consumer(来自provider包),或者Riverpod的FutureProvider,但这些需要引入额外状态管理包,上面的示例是纯Flutter基础实现。 - 存储简单独立的基础类型(比如单个字符串、数字)时,不需要序列化,直接调用
prefs.setString、prefs.getInt等方法即可。
内容的提问来源于stack exchange,提问作者Jad
相关产品推荐
相关产品推荐

