Flutter 数据存储的四种核心方式 · 从 SharedPreferences 到 SQLite:Flutter 数据持久化终极整理

发布于:2025-09-14 ⋅ 阅读:(23) ⋅ 点赞:(0)

  1. Shared Preferences (偏好设置)

这是最简单的方法,用于保存一些简单的键值对。

步骤:

  1. 添加依赖:在 pubspec.yaml 文件中添加:
    dependencies:
      shared_preferences: ^2.2.2 # 请使用最新版本
    
    然后运行 flutter pub get。
  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(); // 清空所有数据
    }
    

优点:简单易用。 缺点:只能存储基本数据类型,不适合大量或复杂数据。


  1. 文件存储 (Files)

用于存储更复杂的数据,比如将对象序列化为 JSON 字符串后存入文件。

步骤:

  1. 添加依赖:需要路径支持包。
    dependencies:
      path_provider: ^2.0.15 # 请使用最新版本
    
  2. 使用方法:
    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);
      }
    }
    

优点:灵活,可以存储任何格式的数据。 缺点:需要手动处理序列化和反序列化,处理大量结构化数据时查询效率低。


  1. SQLite 数据库 (sqflite)

最适合存储大量需要复杂查询的结构化数据。

步骤:

  1. 添加依赖:
    dependencies:
      sqflite: ^2.3.0 # 请使用最新版本
      path_provider: ^2.0.15
      path: ^1.8.3
    
  2. 使用方法(简化示例):
    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)来简化操作。


  1. 云端存储 (Firebase Firestore)

如果你的应用需要在线同步、实时更新或多用户支持,Firebase 是绝佳选择。

步骤:

  1. 在 Firebase 控制台创建项目并配置 Flutter 应用(官方文档很详细)。
  2. 添加依赖:
    dependencies:
      cloud_firestore: ^4.9.1 # 请使用最新版本
    
  3. 使用方法:
    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 应用中的数据保存策略!