SharedPreferences 使用教程¶
SharedPreferences 是 Flutter 官方推荐的轻量级键值对存储,适用于简单配置和用户偏好设置。
一、简介¶
1.1 什么是 SharedPreferences?¶
SharedPreferences 是轻量级数据持久化方案:
- 键值对存储:String, int, double, bool, List
1.2 适用场景¶
- 用户偏好设置(主题、语言)
- 开关状态(首次使用标识、通知开关)
- 简单配置(服务器地址、分页大小)
- 登录状态 Token
- 应用内评分/收藏
不适场景:大量数据、结构化数据、复杂查询
1.3 官方资源¶
| 资源 | 链接 |
|---|---|
| Pub 页面 | https://pub.dev/packages/shared_preferences |
| 官方文档 | https://api.flutter.dev/flutter/shared_preferences/shared_preferences-library.html |
二、安装¶
# pubspec.yaml
dependencies:
shared_preferences: ^2.2.2
flutter pub get
三、基础用法¶
3.1 写入数据¶
import 'package:shared_preferences/shared_preferences.dart';
// 存储字符串
await SharedPreferences.getInstance().then((prefs) {
prefs.setString('username', 'Luke');
});
// 存储数字
prefs.setInt('age', 25);
prefs.setDouble('height', 175.5);
// 存储布尔值
prefs.setBool('isDarkMode', true);
// 存储列表
prefs.setStringList('tags', ['flutter', 'dart', 'getx']);
3.2 读取数据¶
final prefs = await SharedPreferences.getInstance();
// 读取字符串,默认值 ''
String username = prefs.getString('username') ?? '';
// 读取数字,默认值 0
int age = prefs.getInt('age') ?? 0;
double height = prefs.getDouble('height') ?? 0.0;
// 读取布尔值,默认值 false
bool isDarkMode = prefs.getBool('isDarkMode') ?? false;
// 读取列表,默认值 []
List<String> tags = prefs.getStringList('tags') ?? [];
3.3 删除数据¶
final prefs = await SharedPreferences.getInstance();
// 删除单个键
await prefs.remove('username');
// 清空所有数据
await prefs.clear();
3.4 检查键是否存在¶
bool exists = prefs.containsKey('username');
四、进阶用法¶
4.1 存储 JSON 对象¶
import 'dart:convert';
// 存储 Map
Map<String, dynamic> userInfo = {
'id': 1,
'name': 'Luke',
'email': 'luke@example.com'
};
await prefs.setString('userInfo', jsonEncode(userInfo));
// 读取 Map
String? userInfoStr = prefs.getString('userInfo');
if (userInfoStr != null) {
Map<String, dynamic> userInfo = jsonDecode(userInfoStr);
}
4.2 存储 DateTime¶
// 存储 DateTime(转为时间戳)
DateTime lastLogin = DateTime.now();
await prefs.setInt('lastLogin', lastLogin.millisecondsSinceEpoch);
// 读取 DateTime
int? lastLoginMs = prefs.getInt('lastLogin');
if (lastLoginMs != null) {
DateTime lastLogin = DateTime.fromMillisecondsSinceEpoch(lastLoginMs);
}
4.3 批量操作¶
// 批量写入
Future<void> saveSettings({
required String theme,
required String language,
required bool notifications,
}) async {
final prefs = await SharedPreferences.getInstance();
await Future.wait([
prefs.setString('theme', theme),
prefs.setString('language', language),
prefs.setBool('notifications', notifications),
]);
}
五、结合 GetX 使用¶
5.1 创建 Service¶
// lib/services/preferences_service.dart
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
class PreferencesService extends GetxService {
late final SharedPreferences _prefs;
Future<PreferencesService> init() async {
_prefs = await SharedPreferences.getInstance();
return this;
}
// 通用方法
String? getString(String key) => _prefs.getString(key);
Future<bool> setString(String key, String value) => _prefs.setString(key, value);
int? getInt(String key) => _prefs.getInt(key);
Future<bool> setInt(String key, int value) => _prefs.setInt(key, value);
bool? getBool(String key) => _prefs.getBool(key);
Future<bool> setBool(String key, bool value) => _prefs.setBool(key, value);
Future<bool> remove(String key) => _prefs.remove(key);
Future<bool> clear() => _prefs.clear();
// 业务方法
bool get isDarkMode => _prefs.getBool('isDarkMode') ?? false;
Future<void> setDarkMode(bool value) => _prefs.setBool('isDarkMode', value);
String get language => _prefs.getString('language') ?? 'zh';
Future<void> setLanguage(String lang) => _prefs.setString('language', lang);
String? get token => _prefs.getString('token');
Future<void> setToken(String? token) async {
if (token != null) {
await _prefs.setString('token', token);
} else {
await _prefs.remove('token');
}
}
}
5.2 初始化¶
// main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Get.putAsync(() => PreferencesService().init());
runApp(MyApp());
}
5.3 创建 Controller¶
// lib/controllers/theme_controller.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../services/preferences_service.dart';
class ThemeController extends GetxController {
final PreferencesService _prefs = Get.find();
bool get isDarkMode => _prefs.isDarkMode;
ThemeMode get themeMode => isDarkMode ? ThemeMode.dark : ThemeMode.light;
Future<void> toggleTheme() async {
await _prefs.setDarkMode(!isDarkMode);
Get.changeThemeMode(themeMode);
update(); // 通知 UI 更新
}
}
5.4 页面使用¶
class SettingsPage extends StatelessWidget {
final ThemeController themeCtrl = Get.find();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('设置')),
body: ListView(
children: [
Obx(() => SwitchListTile(
title: Text('深色模式'),
subtitle: Text('开启深色主题'),
value: themeCtrl.isDarkMode,
onChanged: (_) => themeCtrl.toggleTheme(),
)),
],
),
);
}
}
六、完整示例:用户设置页面¶
// lib/controllers/settings_controller.dart
import 'dart:convert';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import '../services/preferences_service.dart';
class SettingsController extends GetxController {
final PreferencesService _prefs = Get.find();
// 主题
bool get isDarkMode => _prefs.isDarkMode;
ThemeMode get themeMode => isDarkMode ? ThemeMode.dark : ThemeMode.light;
// 语言
String get language => _prefs.language;
static const languages = ['zh', 'en', 'ja'];
// 通知
bool get notifications => _prefs.getBool('notifications') ?? true;
// 用户信息
Map<String, dynamic>? get userInfo {
final str = _prefs.getString('userInfo');
return str != null ? jsonDecode(str) : null;
}
// 修改主题
Future<void> setDarkMode(bool value) async {
await _prefs.setBool('isDarkMode', value);
Get.changeThemeMode(themeMode);
update();
}
// 修改语言
Future<void> setLanguage(String lang) async {
await _prefs.setString('language', lang);
update();
}
// 修改通知设置
Future<void> setNotifications(bool value) async {
await _prefs.setBool('notifications', value);
update();
}
// 保存用户信息
Future<void> setUserInfo(Map<String, dynamic> info) async {
await _prefs.setString('userInfo', jsonEncode(info));
update();
}
// 退出登录
Future<void> logout() async {
await _prefs.remove('token');
await _prefs.remove('userInfo');
// 跳转到登录页
Get.offAllNamed('/login');
}
}
// lib/pages/settings_page.dart
class SettingsPage extends StatelessWidget {
final SettingsController ctrl = Get.put(SettingsController());
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('设置')),
body: Obx(() => ListView(
children: [
// 主题设置
SwitchListTile(
title: Text('深色模式'),
subtitle: Text('开启后使用深色主题'),
value: ctrl.isDarkMode,
onChanged: ctrl.setDarkMode,
),
Divider(),
// 语言设置
ListTile(
title: Text('语言'),
subtitle: Text(_getLanguageName(ctrl.language)),
trailing: Icon(Icons.chevron_right),
onTap: () => _showLanguageDialog(),
),
Divider(),
// 通知设置
SwitchListTile(
title: Text('推送通知'),
subtitle: Text('接收应用推送消息'),
value: ctrl.notifications,
onChanged: ctrl.setNotifications,
),
Divider(),
// 退出登录
ListTile(
title: Text('退出登录', style: TextStyle(color: Colors.red)),
onTap: () => _confirmLogout(),
),
],
)),
);
}
String _getLanguageName(String code) {
switch (code) {
case 'zh': return '简体中文';
case 'en': return 'English';
case 'ja': return '日本語';
default: return '未知';
}
}
void _showLanguageDialog() {
Get.dialog(AlertDialog(
title: Text('选择语言'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: SettingsController.languages.map((lang) {
return RadioListTile<String>(
title: Text(_getLanguageName(lang)),
value: lang,
groupValue: ctrl.language,
onChanged: (value) {
if (value != null) {
ctrl.setLanguage(value);
Get.back();
}
},
);
}).toList(),
),
));
}
void _confirmLogout() {
Get.dialog(AlertDialog(
title: Text('确认退出'),
content: Text('确定要退出登录吗?'),
actions: [
TextButton(onPressed: () => Get.back(), child: Text('取消')),
ElevatedButton(
onPressed: () {
Get.back();
ctrl.logout();
},
child: Text('退出'),
),
],
));
}
}
七、常见问题¶
7.1 异步初始化¶
SharedPreferences 本身是异步的,建议在应用启动时初始化:
// 方式1:使用 FutureBuilder
FutureBuilder<SharedPreferences>(
future: SharedPreferences.getInstance(),
builder: (context, snapshot) {
if (!snapshot.hasData) return CircularProgressIndicator();
return MyApp(prefs: snapshot.data!);
},
)
// 方式2:在 main 中等待
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final prefs = await SharedPreferences.getInstance();
runApp(MyApp(prefs: prefs));
}
7.2 数据丢失¶
- 卸载应用会清除数据
- 清理应用缓存也会清除数据
- 敏感数据建议加密或使用其他存储方案
7.3 性能优化¶
// 不要频繁读写
// 不好:每次点击都保存
onChanged: (value) {
prefs.setString('key', value); // 频繁写入
}
// 推荐:批量或延迟保存
onChanged: (value) {
_tempValue = value;
Future.delayed(Duration(seconds: 1), () => prefs.setString('key', value));
}
八、总结¶
SharedPreferences 特点:
- ✅ 官方推荐:Flutter 官方推荐
- ✅ 全平台支持:所有平台通用
- ✅ 简单易用:无需初始化
- ✅ 同步 API:无需回调
适用场景: - 轻量配置 - 用户偏好 - 简单状态
不适用场景: - 大量数据 - 结构化数据 - 复杂查询