Flutter 数据存储的四种核心方式 · 从 SharedPreferences 到 SQLite:Flutter 数据持久化终极整理
- Shared Preferences (偏好设置)
这是最简单的方法,用于保存一些简单的键值对。
步骤:
- 添加依赖:在 pubspec.yaml 文件中添加:
然后运行 flutter pub get。dependencies:shared_preferences: ^2.2.2 # 请使用最新版本
- 使用方法:
import 'package:shared_preferences/shared_preferences.dart';// 保存数据 void saveData() async {final prefs = await SharedPreferences.getInstance();await prefs.setInt('counter', 42); // 保存整数await prefs.setBool('isDarkMode', true); // 保存布尔值await prefs.setString('token', 'abc123xyz'); // 保存字符串await prefs.setStringList('favorites', ['item1', 'item2']); // 保存字符串列表 }// 读取数据 void readData() async {final prefs = await SharedPreferences.getInstance();final int? counter = prefs.getInt('counter');final bool? isDarkMode = prefs.getBool('isDarkMode');final String? token = prefs.getString('token');final List<String>? favorites = prefs.getStringList('favorites');print('Counter: $counter');print('isDarkMode: $isDarkMode');print('Token: $token');print('Favorites: $favorites'); }// 删除数据 void removeData() async {final prefs = await SharedPreferences.getInstance();await prefs.remove('counter'); // 删除单个键// await prefs.clear(); // 清空所有数据 }
优点:简单易用。 缺点:只能存储基本数据类型,不适合大量或复杂数据。
- 文件存储 (Files)
用于存储更复杂的数据,比如将对象序列化为 JSON 字符串后存入文件。
步骤:
- 添加依赖:需要路径支持包。
dependencies:path_provider: ^2.0.15 # 请使用最新版本
- 使用方法:
import 'dart:io'; import 'dart:convert'; // 用于 JSON 编码解码 import 'package:path_provider/path_provider.dart';// 定义一个数据模型 class Settings {final String username;final int score;Settings({required this.username, required this.score});// 将对象转为 Map,便于转为 JSONMap<String, dynamic> toJson() => {'username': username,'score': score,};// 从 Map/JSON 创建对象factory Settings.fromJson(Map<String, dynamic> json) {return Settings(username: json['username'],score: json['score'],);} }// 获取应用文档目录的路径 Future<String> get _localPath async {final directory = await getApplicationDocumentsDirectory();return directory.path; }// 获取文件的引用 Future<File> get _localFile async {final path = await _localPath;return File('$path/settings.json'); }// 写入文件(保存数据) Future<File> saveSettings(Settings settings) async {final file = await _localFile;// 将对象转为 JSON 字符串final jsonString = jsonEncode(settings.toJson());// 将字符串写入文件return file.writeAsString(jsonString); }// 读取文件(读取数据) Future<Settings> readSettings() async {try {final file = await _localFile;// 读取文件内容final contents = await file.readAsString();// 将 JSON 字符串解析为 Mapfinal jsonMap = jsonDecode(contents) as Map<String, dynamic>;// 从 Map 创建 Settings 对象return Settings.fromJson(jsonMap);} catch (e) {// 如果文件不存在或出错,返回一个默认值return Settings(username: 'Guest', score: 0);} }
优点:灵活,可以存储任何格式的数据。 缺点:需要手动处理序列化和反序列化,处理大量结构化数据时查询效率低。
- SQLite 数据库 (sqflite)
最适合存储大量需要复杂查询的结构化数据。
步骤:
- 添加依赖:
dependencies:sqflite: ^2.3.0 # 请使用最新版本path_provider: ^2.0.15path: ^1.8.3
- 使用方法(简化示例):
import 'package:sqflite/sqflite.dart'; import 'package:path/path.dart';class Dog {final int? id;final String name;final int age;Dog({this.id, required this.name, required this.age});Map<String, dynamic> toMap() {return {'id': id,'name': name,'age': age,};}// ... fromMap 方法 }class DatabaseHelper {static final _databaseName = "my_database.db";static final _databaseVersion = 1;static final table = 'dogs';static final columnId = 'id';static final columnName = 'name';static final columnAge = 'age';// 单例模式DatabaseHelper._privateConstructor();static final DatabaseHelper instance = DatabaseHelper._privateConstructor();static Database? _database;Future<Database> get database async {if (_database != null) return _database!;_database = await _initDatabase();return _database!;}_initDatabase() async {String path = join(await getDatabasesPath(), _databaseName);return await openDatabase(path,version: _databaseVersion,onCreate: _onCreate,);}// 创建表Future _onCreate(Database db, int version) async {await db.execute('''CREATE TABLE $table ($columnId INTEGER PRIMARY KEY AUTOINCREMENT,$columnName TEXT NOT NULL,$columnAge INTEGER NOT NULL)''');}// 插入一条数据(C)Future<int> insert(Dog dog) async {Database db = await instance.database;return await db.insert(table, dog.toMap());}// 查询所有数据(R)Future<List<Dog>> queryAll() async {Database db = await instance.database;List<Map> maps = await db.query(table);return maps.map((map) => Dog.fromMap(map)).toList();}// 更新数据(U)// 删除数据(D)// ... 其他方法 }
优点:功能强大,查询高效,适合复杂数据。 缺点:需要编写较多的样板代码(Boilerplate Code)。可以考虑使用更高级的封装库,如drift(原 moor)来简化操作。
- 云端存储 (Firebase Firestore)
如果你的应用需要在线同步、实时更新或多用户支持,Firebase 是绝佳选择。
步骤:
- 在 Firebase 控制台创建项目并配置 Flutter 应用(官方文档很详细)。
- 添加依赖:
dependencies:cloud_firestore: ^4.9.1 # 请使用最新版本
- 使用方法:
import 'package:cloud_firestore/cloud_firestore.dart';// 获取 Firestore 实例 final FirebaseFirestore firestore = FirebaseFirestore.instance;// 添加数据 void addUser() {firestore.collection('users').add({'name': 'John Doe','age': 30,}).then((value) => print("User Added")).catchError((error) => print("Failed to add user: $error")); }// 读取数据(实时监听) Stream<QuerySnapshot> readUsers() {return firestore.collection('users').snapshots(); // 返回一个流,数据变化时会自动推送新数据 }// 在 UI 中使用 StreamBuilder 来显示实时数据 Widget build(BuildContext context) {return StreamBuilder<QuerySnapshot>(stream: readUsers(),builder: (context, snapshot) {if (snapshot.hasError) {return Text('Something went wrong');}if (snapshot.connectionState == ConnectionState.waiting) {return Text("Loading");}return ListView(children: snapshot.data!.docs.map((DocumentSnapshot document) {Map<String, dynamic> data = document.data()! as Map<String, dynamic>;return ListTile(title: Text(data['name']),subtitle: Text('Age: ${data['age']}'),);}).toList(),);},); }
优点:无需自己搭建后端,支持实时同步,功能强大。 缺点:需要网络连接,会产生费用(有免费额度)。
总结与建议
· 简单配置/用户偏好:毫不犹豫地使用 shared_preferences。
· 缓存图片或下载文件:使用文件存储。
· 复杂的本地数据(如待办事项、笔记、通讯录):使用 sqflite 数据库。如果你觉得 sqflite 代码太繁琐,可以研究一下 hive(一个非常快且无样板代码的键值数据库)或 drift(一个强大的 SQLite 封装库)。
· 需要在线同步、实时协作:使用 Firebase Firestore。
· 综合应用:一个应用通常会组合使用多种方案。例如,用 shared_preferences 存用户主题设置,用 sqflite 存本地文章草稿,同时用 Firestore 将最终文章同步到云端。
希望这份整理能帮助你清晰地规划 Flutter 应用中的数据保存策略!