- 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,便于转为 JSON Map<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 字符串解析为 Map final 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.15 path: ^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 应用中的数据保存策略!