Flutter_学习记录_本地存储数据

前言

在移动应用开发中,存储数据是一个非常重要的环节。Flutter 作为一种跨平台的移动应用开发框架,也提供了多种方式来存储数据。存储的数据可以是简单的键值对,也可以是复杂的对象。在本地存储方面,Flutter 支持多种不同的方式,包括 Shared Preferences、SQLite、文件存储以及 Hive 等。

本文将围绕 Flutter 中本地存储的各种方式展开,并通过具体的实例来说明如何实现本地存储功能。我们将介绍每种存储方式的特点、使用场景以及如何在 Flutter 中实现它们。

目录

  1. SharedPreferences
    • 1.1 介绍
    • 1.2 使用场景
    • 1.3 使用示例
  2. SQLite
    • 2.1 介绍
    • 2.2 使用场景
    • 2.3 使用示例
  3. 文件存储
    • 3.1 介绍
    • 3.2 使用场景
    • 3.3 使用示例
  4. Hive
    • 4.1 介绍
    • 4.2 使用场景
    • 4.3 使用示例
  5. 总结

SharedPreferences

1.1 介绍

SharedPreferences 是 Android 和 iOS 平台上一种轻量级的数据存储方式,通常用于保存一些简单的数据,如用户设置、标志位等。它本质上是通过键值对的方式将数据存储在设备的持久化存储中,具有较小的数据存储量和较快的读写速度。Flutter 提供了 shared_preferences 插件来访问该功能。

1.2 使用场景

  • 用户设置,如主题、语言、是否启用通知等。
  • 存储应用的配置信息。
  • 存储简单的标志位,例如用户是否首次使用应用、是否需要进行引导页等。

1.3 使用示例

dartCopy Code
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() => runApp(MyApp()); class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { bool _isFirstLaunch = false; @override void initState() { super.initState(); _loadFirstLaunchStatus(); } // 加载首次启动标志 void _loadFirstLaunchStatus() async { SharedPreferences prefs = await SharedPreferences.getInstance(); bool isFirstLaunch = prefs.getBool('isFirstLaunch') ?? true; setState(() { _isFirstLaunch = isFirstLaunch; }); } // 设置首次启动标志 void _setFirstLaunchStatus() async { SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setBool('isFirstLaunch', false); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('SharedPreferences 示例')), body: Center( child: _isFirstLaunch ? ElevatedButton( onPressed: () { _setFirstLaunchStatus(); setState(() { _isFirstLaunch = false; }); }, child: Text('第一次启动,设置标志位'), ) : Text('欢迎回来!'), ), ), ); } }

解释

  • 使用 SharedPreferences 插件,我们可以存储一个布尔值 isFirstLaunch 来判断应用是否是第一次启动。
  • 当用户首次启动应用时,展示一个按钮,并且在点击后设置该标志位为 false,并改变界面显示内容。

使用优缺点

优点

  • 使用简单,适合存储少量简单数据。
  • 存储在设备上,应用退出后数据仍然可用。

缺点

  • 适合存储小量数据,数据量过大会影响性能。
  • 不适合存储复杂数据结构,如列表或对象。

SQLite

2.1 介绍

SQLite 是一种轻量级的关系型数据库,支持 SQL 查询语言,适合需要存储结构化数据的应用。Flutter 中可以通过 sqflite 插件来操作 SQLite 数据库。

2.2 使用场景

  • 存储大量的结构化数据。
  • 数据之间有关系,如用户信息和订单数据。
  • 需要复杂查询和事务管理的应用。

2.3 使用示例

首先,在 pubspec.yaml 中添加 sqflite 依赖:

yamlCopy Code
dependencies: sqflite: ^2.0.0+3 path_provider: ^2.0.10

接着,创建数据库并执行增、查、改、删操作。

dartCopy Code
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:sqflite/sqflite.dart'; import 'package:path/path.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: TodoPage(), ); } } class TodoPage extends StatefulWidget { @override _TodoPageState createState() => _TodoPageState(); } class _TodoPageState extends State<TodoPage> { Database? _database; @override void initState() { super.initState(); _initializeDatabase(); } // 初始化数据库 void _initializeDatabase() async { var databasesPath = await getDatabasesPath(); String path = join(databasesPath, 'todo.db'); _database = await openDatabase(path, version: 1, onCreate: (Database db, int version) async { await db.execute(''' CREATE TABLE todos ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, description TEXT ) '''); }); } // 插入一条记录 Future<void> _insertTodo() async { await _database?.insert('todos', { 'title': 'Learn Flutter', 'description': 'Study the basics of Flutter and Dart' }); setState(() {}); } // 查询所有记录 Future<List<Map<String, dynamic>>> _getTodos() async { return await _database?.query('todos') ?? []; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('SQLite 示例')), body: FutureBuilder<List<Map<String, dynamic>>>( future: _getTodos(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } if (!snapshot.hasData || snapshot.data!.isEmpty) { return Center(child: Text('暂无待办事项')); } return ListView.builder( itemCount: snapshot.data!.length, itemBuilder: (context, index) { var todo = snapshot.data![index]; return ListTile( title: Text(todo['title']), subtitle: Text(todo['description']), ); }, ); }, ), floatingActionButton: FloatingActionButton( onPressed: _insertTodo, child: Icon(Icons.add), ), ); } }

解释

  • 该示例使用 SQLite 存储待办事项数据,包括 idtitledescription
  • TodoPage 页面初始化时创建数据库,并提供了插入新待办事项的功能,同时也能展示所有待办事项。

使用优缺点

优点

  • 支持结构化数据存储,适合存储大量数据。
  • 支持 SQL 查询,能够处理复杂的数据操作。

缺点

  • 数据库的操作相对较重,不适合非常简单的数据存储。
  • 需要处理数据库的版本控制和迁移。

文件存储

3.1 介绍

Flutter 中的文件存储可以通过 path_provider 插件来获取应用的文档目录或者临时目录。通过这些目录,我们可以存储文本文件、二进制文件等。

3.2 使用场景

  • 存储文件或文档。
  • 存储日志文件。
  • 存储多媒体文件(如图片、音频文件等)。

3.3 使用示例

dartCopy Code
import 'dart:io'; import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: FileStoragePage(), ); } } class FileStoragePage extends StatefulWidget { @override _FileStoragePageState createState() => _FileStoragePageState(); } class _FileStoragePageState extends State<FileStoragePage> { late File _file; String _fileContent = ''; @override void initState() { super.initState(); _initializeFile(); } // 初始化文件 void _initializeFile() async { final directory = await getApplicationDocumentsDirectory(); _file = File('${directory.path}/example.txt'); if (await _file.exists()) { _fileContent = await _file.readAsString(); setState(() {}); } } // 写入文件 void _writeToFile(String content) async { await _file.writeAsString(content); setState(() { _fileContent = content; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('文件存储示例')), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ Text('文件内容:$_fileContent'), SizedBox(height: 20), ElevatedButton( onPressed: () => _writeToFile('Hello, Flutter!'), child: Text('写入文件'), ), ], ), ), ); } }

解释

  • 该示例演示了如何使用 path_provider 插件来获取应用的文档目录,并创建一个文件 example.txt
  • 我们可以在文件中写入数据,并读取该文件内容。

使用优缺点

优点

  • 可以存储任意类型的文件,包括文本、二进制数据等。
  • 存储较大数据时比数据库更加高效。

缺点

  • 不适合存储结构化数据,查询、更新不如数据库方便。
  • 需要手动管理文件路径和文件内容。

Hive

4.1 介绍

Hive 是一个轻量级的 NoSQL 数据库,特别适合存储简单的键值对数据,也支持存储复杂数据结构。它支持跨平台,能够在 Flutter 中高效地存储和查询数据。

4.2 使用场景

  • 存储简单的键值对数据。
  • 适合存储大量的小数据(如缓存、配置数据等)。
  • 需要快速存储和检索的场景。

4.3 使用示例

首先,在 pubspec.yaml 中添加 hivehive_flutter 依赖:

yamlCopy Code
dependencies: hive: ^2.0.0 hive_flutter: ^1.1.0

接着,使用 Hive 存储数据:

dartCopy Code
import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; import 'package:hive_flutter/hive_flutter.dart'; void main() async { await Hive.initFlutter(); runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: HiveStoragePage(), ); } } class HiveStoragePage extends StatefulWidget { @override _HiveStoragePageState createState() => _HiveStoragePageState(); } class _HiveStoragePageState extends State<HiveStoragePage> { late Box<String> _box; @override void initState() { super.initState(); _initializeHive(); } // 初始化 Hive void _initializeHive() async { _box = await Hive.openBox('myBox'); setState(() {}); } // 写入数据 void _writeToHive(String key, String value) { _box.put(key, value); } // 获取数据 String _readFromHive(String key) { return _box.get(key, defaultValue: 'No Data'); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Hive 示例')), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ Text('存储的值:${_readFromHive('myKey')}'), ElevatedButton( onPressed: () => _writeToHive('myKey', 'Hello, Hive!'), child: Text('写入数据'), ), ], ), ), ); } }

解释

  • 在 Hive 中,我们通过 Box 来存储和检索数据。每个 Box 是一个键值对集合,可以存储各种类型的数据。
  • 在该示例中,我们在 Hive 中存储了一个字符串键值对,并通过按钮点击操作来修改它。

使用优缺点

优点

  • 快速、高效,适合存储大量简单数据。
  • 易于使用,尤其适合存储简单的键值对数据。
  • 支持复杂的数据类型,如对象、列表等。

缺点

  • 适合简单数据的存储,不适合进行复杂查询操作。
  • 比较适合存储数据量较小的应用场景。

总结

在本文中,我们介绍了 Flutter 中几种常见的本地存储方式,包括 SharedPreferencesSQLite、文件存储和 Hive,并通过具体示例说明了它们的使用方法和适用场景。

  • SharedPreferences 适合存储简单的键值对数据,常用于存储用户设置和小规模的应用状态。
  • SQLite 适合存储结构化的数据,适用于复杂数据的查询和操作。
  • 文件存储适用于存储文件、日志等较大数据。
  • Hive 是一个高效的键值对存储方案,适合存储简单的数据和快速存取。

每种存储方式都有其优缺点,在实际开发中,应根据数据的性质、存储量以及查询的复杂度来选择合适的存储方案。