Flutter开发如何使用单例模式实现数据库管理类

前端 潘老师 4周前 (03-26) 16 ℃ (0) 扫码查看

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的相关知识,共同进步!


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/front/16327.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】