Flutter_学习记录_本地存储数据
前言
在移动应用开发中,存储数据是一个非常重要的环节。Flutter 作为一种跨平台的移动应用开发框架,也提供了多种方式来存储数据。存储的数据可以是简单的键值对,也可以是复杂的对象。在本地存储方面,Flutter 支持多种不同的方式,包括 Shared Preferences、SQLite、文件存储以及 Hive 等。
本文将围绕 Flutter 中本地存储的各种方式展开,并通过具体的实例来说明如何实现本地存储功能。我们将介绍每种存储方式的特点、使用场景以及如何在 Flutter 中实现它们。
目录
- SharedPreferences
- 1.1 介绍
- 1.2 使用场景
- 1.3 使用示例
- SQLite
- 2.1 介绍
- 2.2 使用场景
- 2.3 使用示例
- 文件存储
- 3.1 介绍
- 3.2 使用场景
- 3.3 使用示例
- Hive
- 4.1 介绍
- 4.2 使用场景
- 4.3 使用示例
- 总结
SharedPreferences
1.1 介绍
SharedPreferences
是 Android 和 iOS 平台上一种轻量级的数据存储方式,通常用于保存一些简单的数据,如用户设置、标志位等。它本质上是通过键值对的方式将数据存储在设备的持久化存储中,具有较小的数据存储量和较快的读写速度。Flutter 提供了 shared_preferences
插件来访问该功能。
1.2 使用场景
- 用户设置,如主题、语言、是否启用通知等。
- 存储应用的配置信息。
- 存储简单的标志位,例如用户是否首次使用应用、是否需要进行引导页等。
1.3 使用示例
dartCopy Codeimport '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 Codedependencies:
sqflite: ^2.0.0+3
path_provider: ^2.0.10
接着,创建数据库并执行增、查、改、删操作。
dartCopy Codeimport '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 存储待办事项数据,包括
id
、title
和description
。 TodoPage
页面初始化时创建数据库,并提供了插入新待办事项的功能,同时也能展示所有待办事项。
使用优缺点
优点:
- 支持结构化数据存储,适合存储大量数据。
- 支持 SQL 查询,能够处理复杂的数据操作。
缺点:
- 数据库的操作相对较重,不适合非常简单的数据存储。
- 需要处理数据库的版本控制和迁移。
文件存储
3.1 介绍
Flutter 中的文件存储可以通过 path_provider
插件来获取应用的文档目录或者临时目录。通过这些目录,我们可以存储文本文件、二进制文件等。
3.2 使用场景
- 存储文件或文档。
- 存储日志文件。
- 存储多媒体文件(如图片、音频文件等)。
3.3 使用示例
dartCopy Codeimport '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
中添加 hive
和 hive_flutter
依赖:
yamlCopy Codedependencies:
hive: ^2.0.0
hive_flutter: ^1.1.0
接着,使用 Hive 存储数据:
dartCopy Codeimport '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 中几种常见的本地存储方式,包括 SharedPreferences
、SQLite
、文件存储和 Hive
,并通过具体示例说明了它们的使用方法和适用场景。
SharedPreferences
适合存储简单的键值对数据,常用于存储用户设置和小规模的应用状态。SQLite
适合存储结构化的数据,适用于复杂数据的查询和操作。- 文件存储适用于存储文件、日志等较大数据。
Hive
是一个高效的键值对存储方案,适合存储简单的数据和快速存取。
每种存储方式都有其优缺点,在实际开发中,应根据数据的性质、存储量以及查询的复杂度来选择合适的存储方案。