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


  1. Shared Preferences (偏好设置)

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

步骤:

  1. 添加依赖:在 pubspec.yaml 文件中添加:

    yaml 复制代码
    dependencies:
      shared_preferences: ^2.2.2 # 请使用最新版本

    然后运行 flutter pub get。

  2. 使用方法:

    dart 复制代码
    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. 添加依赖:需要路径支持包。

    yaml 复制代码
    dependencies:
      path_provider: ^2.0.15 # 请使用最新版本
  2. 使用方法:

    dart 复制代码
    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. 添加依赖:

    yaml 复制代码
    dependencies:
      sqflite: ^2.3.0 # 请使用最新版本
      path_provider: ^2.0.15
      path: ^1.8.3
  2. 使用方法(简化示例):

    dart 复制代码
    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. 添加依赖:

    yaml 复制代码
    dependencies:
      cloud_firestore: ^4.9.1 # 请使用最新版本
  3. 使用方法:

    dart 复制代码
    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 应用中的数据保存策略!

相关推荐
程序员Ctrl喵18 小时前
异步编程:Event Loop 与 Isolate 的深层博弈
开发语言·flutter
前端不太难19 小时前
Flutter 如何设计可长期维护的模块边界?
flutter
小蜜蜂嗡嗡20 小时前
flutter列表中实现置顶动画
flutter
始持20 小时前
第十二讲 风格与主题统一
前端·flutter
始持20 小时前
第十一讲 界面导航与路由管理
flutter·vibecoding
始持20 小时前
第十三讲 异步操作与异步构建
前端·flutter
新镜21 小时前
【Flutter】 视频视频源横向、竖向问题
flutter
黄林晴1 天前
Compose Multiplatform 1.10 发布:统一 Preview、Navigation 3、Hot Reload 三箭齐发
android·flutter
Swift社区1 天前
Flutter 应该按功能拆,还是按技术层拆?
flutter
肠胃炎1 天前
树形选择器组件封装
前端·flutter