如何在Flutter中使用SQLite?(含代码示例)
Flutter 中 SQLite 的使用详解
在 Flutter 应用中,如果需要本地存储结构化数据,SQLite 是一个非常好的选择。SQLite 是一个轻量级的、嵌入式的关系型数据库,无需单独的服务器进程,直接在应用内部进行数据操作。本文将详细介绍如何在 Flutter 项目中使用 SQLite,并提供完整的代码示例。
1. 添加依赖
首先,我们需要在 pubspec.yaml
文件中添加 sqflite
和 path_provider
插件的依赖:
yaml
dependencies:
flutter:
sdk: flutter
sqflite: ^2.0.0+3 # 使用最新版本
path_provider: ^2.0.0 # 使用最新版本
解释:
* sqflite
: Flutter 官方推荐的 SQLite 插件,提供了操作 SQLite 数据库的 API。
* path_provider
: 用于获取应用的文件系统路径,例如文档目录(用于存储数据库文件)。
添加依赖后,在终端运行 flutter pub get
命令来安装这些插件。
2. 创建数据库帮助类 (Database Helper)
为了更好地组织代码和管理数据库操作,我们通常会创建一个数据库帮助类。这个类将负责:
- 打开/创建数据库
- 定义数据表结构 (创建表)
- 执行 CRUD 操作 (Create, Read, Update, Delete)
以下是一个 DatabaseHelper
类的示例:
```dart
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
class DatabaseHelper {
// 单例模式
DatabaseHelper._privateConstructor();
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
static Database? _database;
// 获取数据库,如果不存在则创建
Future
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
}
// 初始化数据库
Future
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, 'my_database.db'); // 数据库文件名
return await openDatabase(
path,
version: 1, // 数据库版本号,用于数据库升级
onCreate: _onCreate, // 创建数据库表的回调函数
);
}
// 创建数据库表
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE dogs (
id INTEGER PRIMARY KEY,
name TEXT,
age INTEGER
)
''');
}
// 插入数据
Future
Database db = await instance.database;
return await db.insert('dogs', dog);
}
// 查询所有数据
Future>> queryAllDogs() async {
Database db = await instance.database;
return await db.query('dogs');
}
// 根据 ID 查询
Future
// 更新数据
Future
Database db = await instance.database;
int id = dog['id'];
return await db.update(
'dogs',
dog,
where: 'id = ?',
whereArgs: [id],
);
}
// 删除数据
Future
Database db = await instance.database;
return await db.delete(
'dogs',
where: 'id = ?',
whereArgs: [id],
);
}
// 删除所有数据
Future
Database db = await instance.database;
return await db.delete('dogs');
}
}
```
代码解释:
- 单例模式:
DatabaseHelper._privateConstructor()
和static final DatabaseHelper instance = ...
确保整个应用中只有一个DatabaseHelper
实例。 get database
: 懒加载数据库,只有在第一次需要访问数据库时才会创建。_initDatabase()
:getApplicationDocumentsDirectory()
: 获取应用文档目录的路径。join(documentsDirectory.path, 'my_database.db')
: 构建数据库文件的完整路径。openDatabase()
: 打开数据库(如果不存在则创建)。version
: 数据库版本号。当数据库结构需要变更时(例如添加新表或修改表结构),应增加版本号。onCreate
: 创建数据库时执行的回调函数,通常用于创建表。
_onCreate()
: 使用 SQL 语句创建名为dogs
的表,包含id
(主键),name
, 和age
列。- CRUD Methods: 实现了插入 (insertDog), 查询所有 (queryAllDogs), 根据ID查询(queryDogById), 更新 (updateDog), 删除 (deleteDog) 和删除所有 (deleteAllDogs) 的基本数据库操作。 这些方法都使用了
sqflite
提供的 API。
3. 使用 DatabaseHelper
现在我们可以在 Flutter 应用中使用 DatabaseHelper
类来操作数据库了。
```dart
import 'package:flutter/material.dart';
import 'database_helper.dart'; // 导入 DatabaseHelper
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State
final dbHelper = DatabaseHelper.instance; // 获取 DatabaseHelper 实例
List
bool _isLoading = true;
@override
void initState() {
super.initState();
_loadDogs();
}
Future
_allDogs = await dbHelper.queryAllDogs();
setState(() {
_isLoading = false;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SQLite Example'),
),
body: _isLoading ? Center(child:CircularProgressIndicator()) : ListView.builder(
itemCount: _allDogs.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(_allDogs[index]['name']),
subtitle: Text('Age: ${_allDogs[index]['age']}'),
trailing: IconButton(icon: Icon(Icons.delete), onPressed: (){
_deleteDog(_allDogs[index]['id']);
},),
onTap: () {
_showUpdateDialog(_allDogs[index]);
},
);
},
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
_showInsertDialog();
},
),
);
}
// 显示插入数据的对话框
void _showInsertDialog() {
final nameController = TextEditingController();
final ageController = TextEditingController();
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Add Dog'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: nameController,
decoration: InputDecoration(labelText: 'Name'),
),
TextField(
controller: ageController,
decoration: InputDecoration(labelText: 'Age'),
keyboardType: TextInputType.number,
),
],
),
actions: [
TextButton(
child: Text('Cancel'),
onPressed: () => Navigator.of(context).pop(),
),
TextButton(
child: Text('Add'),
onPressed: () async {
await _insertDog(nameController.text, int.parse(ageController.text));
Navigator.of(context).pop();
},
),
],
);
},
);
}
//插入
Future
Map
'name': name,
'age': age,
};
await dbHelper.insertDog(dog);
_loadDogs();
}
// 删除
Future
await dbHelper.deleteDog(id);
_loadDogs();
}
//显示更新对话框
void _showUpdateDialog(Map
final nameController = TextEditingController(text: dog['name']);
final ageController = TextEditingController(text: dog['age'].toString());
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Update Dog'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: nameController,
decoration: InputDecoration(labelText: 'Name'),
),
TextField(
controller: ageController,
decoration: InputDecoration(labelText: 'Age'),
keyboardType: TextInputType.number,
),
],
),
actions: [
TextButton(
child: Text('Cancel'),
onPressed: () => Navigator.of(context).pop(),
),
TextButton(
child: Text('Update'),
onPressed: () async {
await _updateDog(dog['id'] ,nameController.text, int.parse(ageController.text));
Navigator.of(context).pop();
},
),
],
);
},
);
}
//更新
Future
Map
'id' : id,
'name': name,
'age': age,
};
await dbHelper.updateDog(updatedDog);
_loadDogs();
}
}
```
代码解释:
- 导入
DatabaseHelper
: 引入我们之前创建的数据库帮助类。 - 获取
DatabaseHelper
实例:final dbHelper = DatabaseHelper.instance;
initState
: 初始化时加载数据。_loadDogs
: 使用dbHelper.queryAllDogs()
查询所有数据, 并刷新UI。ListView.builder
: 将查询到的狗狗数据列表显示在ListView
中。_insertDog
: 插入数据到数据库。_deleteDog
: 根据id删除数据。_showInsertDialog
: 显示对话框让用户输入新狗狗的信息。FloatingActionButton
: 点击按钮时,显示插入数据的对话框。_showUpdateDialog
: 显示更新对话框。_updateDog
: 更新数据库。ListTile
: 点击进入更新页面,长按删除。
4. 数据库升级 (Database Upgrade)
当你的应用需要更新数据库结构时(例如添加新表、修改表结构、删除表),你需要:
- 增加
_initDatabase()
方法中的version
参数的值。 - 在
onUpgrade
回调函数中编写升级逻辑。onUpgrade
会在数据库版本号增加时被调用。
示例 (假设我们需要在 dogs
表中添加一个 breed
列):
```dart
// ... (DatabaseHelper 类中的其他代码) ...
Future
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, 'my_database.db');
return await openDatabase(
path,
version: 2, // 增加版本号
onCreate: _onCreate,
onUpgrade: _onUpgrade, // 添加 onUpgrade 回调
);
}
Future _onUpgrade(Database db, int oldVersion, int newVersion) async {
if (oldVersion < 2) {
await db.execute('ALTER TABLE dogs ADD COLUMN breed TEXT');
}
}
// ... (DatabaseHelper 类中的其他代码) ...
```
解释:
version: 2
: 我们将数据库版本号从 1 增加到 2。onUpgrade: _onUpgrade
: 指定onUpgrade
回调函数。_onUpgrade
:oldVersion
: 旧的数据库版本号。newVersion
: 新的数据库版本号。if (oldVersion < 2)
: 检查旧版本是否小于 2,如果是,则执行升级操作。await db.execute('ALTER TABLE dogs ADD COLUMN breed TEXT');
: 使用ALTER TABLE
语句向dogs
表添加breed
列。- 通过
if
判断可以逐步升级, 比如从1升级到3, 会执行oldVersion < 2
和oldVersion < 3
的代码
总结
本文详细介绍了在 Flutter 中使用 SQLite 的方法,包括添加依赖、创建数据库帮助类、执行 CRUD 操作以及数据库升级。通过这些步骤,你可以轻松地在 Flutter 应用中实现本地数据存储。 使用SQLite可以很好的持久化保存数据,并且可以结构化查询,对于较复杂的数据存储需求非常适合。
注意:
* 在实际应用中,建议对数据库操作进行错误处理(try-catch),并根据需要添加更详细的日志记录。
* getApplicationDocumentsDirectory()
返回的是应用专属的文档目录, 应用卸载后数据会被删除。 如果希望数据在应用卸载后仍然保留, 可以考虑使用其他路径, 但需要注意权限问题。
* 对于更复杂的数据库操作(例如事务、多表连接), 请参考 sqflite
插件的官方文档。
* 如果数据量非常大,可以考虑分批加载、分页显示等优化措施。