章
目
录
Flutter开发过程中,对数据的存储和管理很重要。SQLite作为轻量级数据库,常被用于移动应用的数据持久化。今天咱们就来聊聊如何用单例模式编写一个数据库管理类,实现对SQLite数据库的高效管理。
单例模式与类的定义
在Flutter里,咱们创建了一个DatabaseHelper
类,专门用来管理数据库的初始化和访问。这里用到了单例模式,简单来说,单例模式就是让这个类在整个应用里只有一个实例,这样能避免重复创建,节省资源。
来看代码:
static final DatabaseHelper instance = DatabaseHelper._();
static Database? _database;
DatabaseHelper._();
这里的instance
是一个静态且不可变的实例,代表DatabaseHelper
的唯一实例。构造函数DatabaseHelper._()
前面加了下划线,这是私有构造函数的标志,它的作用是防止外部随意创建这个类的实例。想要获取这个唯一实例,在代码里通过DatabaseHelper.instance
就可以访问到。而_database
是个静态变量,用来存放数据库实例,刚开始它的值是null
,意味着数据库还没初始化。
获取数据库实例
要获取数据库实例,咱们写了一个异步的getter方法:
Future<Database> get database async {
_database ??= await _initDatabase();
return _database!;
}
这个方法是这么工作的:当代码里调用database
时,如果_database
的值是null
,就说明数据库还没初始化,这时会调用_initDatabase()
方法进行初始化操作,并且把初始化后的结果赋值给_database
。这里用了??=
操作符,它的作用是确保_database
只会被初始化一次,这就是懒加载,只有真正需要用数据库的时候才去初始化它,避免了不必要的资源浪费。最后返回的_database!
,表示返回一个肯定不为空的数据库实例。
显式初始化数据库
为了能在应用启动时就提前初始化数据库,避免使用时出现延迟,我们还写了一个方法:
Future<void> init() async {
await database;
}
init()
方法是个异步方法,它里面调用了await database
,这会触发前面提到的database
的getter方法,从而确保数据库被初始化。这样在应用启动阶段调用这个方法,就能提前把数据库准备好。
数据库初始化的具体逻辑
数据库的初始化逻辑在下面这个私有方法里:
Future<Database> _initDatabase() async {
final dbPath = await getDatabasesPath();
final path = join(dbPath, 'rental_management.db');
return await openDatabase(
path,
version: 4,
onCreate: _createDatabase,
onUpgrade: _upgradeDatabase,
);
}
首先,通过getDatabasesPath()
获取设备上默认的数据库存储路径,然后用join(dbPath, 'rental_management.db')
把路径和数据库文件名拼在一起,得到完整的数据库文件路径。
接着调用openDatabase()
方法,这是Flutter中sqflite
插件提供的,用来打开或者创建数据库。这里面几个参数很重要:path
就是刚刚拼好的数据库文件完整路径;version
代表数据库版本号,这里设置为4
,如果版本号变了,就会触发onUpgrade
回调;onCreate
是数据库首次创建时会调用的回调函数,一般用来初始化表结构;onUpgrade
则是在数据库版本升级时调用,用于处理数据迁移等操作。
数据库的创建与升级
虽然文章里没有给出_createDatabase
和_upgradeDatabase
的完整代码,但咱们来看看它们大概的作用。
创建数据库表结构
_createDatabase
方法在数据库首次创建时会被调用,主要用来执行SQL语句创建表结构。比如说:
Future<void> _createDatabase(Database db, int version) async {
await db.execute('''
CREATE TABLE rentals (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
price REAL NOT NULL
)
''');
}
这段代码就是在创建一个名为rentals
的表,里面有id
(自增长的主键)、name
(不能为空的文本字段)和price
(不能为空的实数类型字段)这几个字段。
处理数据库升级
_upgradeDatabase
方法在数据库版本升级时会被调用,用来处理数据迁移的事情,比如添加新表、修改现有表结构。举个例子:
Future<void> _upgradeDatabase(Database db, int oldVersion, int newVersion) async {
if (oldVersion < 2) {
await db.execute('ALTER TABLE rentals ADD COLUMN description TEXT');
}
if (oldVersion < 3) {
await db.execute('CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT)');
}
}
这段代码表示,如果旧版本小于2
,就给rentals
表添加一个description
字段;如果旧版本小于3
,就创建一个新表users
。
总结
这篇文章介绍的代码,核心就是用单例模式管理SQLite数据库的初始化和访问。这种方式有不少优点:
- 单例模式保障:通过私有构造函数和静态实例,保证了整个应用里数据库管理类只有一个实例。
- 懒加载特性:数据库只有在第一次被访问时才会初始化,减少了不必要的资源消耗。
- 版本管理支持:能够对数据库版本进行控制,处理好创建和升级的逻辑。
- 异步操作优势:所有数据库操作都是异步的,不会阻塞主线程,保证了应用的流畅运行。
这种设计模式在Flutter开发,尤其是需要持久化数据的场景里,应用非常广泛。希望大家通过这篇文章,对Flutter开发中数据库管理有更深入的理解,也欢迎大家一起交流学习Flutter的相关知识,共同进步!