End

Flutter 陈航 25-持久化 文件 SP 数据库 sqflite

本文地址


目录

25 | 本地存储与数据库的使用

Flutter 提供了三种数据持久化方法,即文件、SharedPreferences 与数据库。

文件

需要引入 path_provider

Flutter 提供了两种文件存储的目录:

  • 临时目录:可以随时清除,在 Android 上对应着 getCacheDir 返回的值
  • 文档目录:只有在删除应用程序时才会被清除,在 Android 上对应着 AppData 目录
void testFile() async {
  // 文件读写是耗时操作,需要在异步环境下进行
  Directory directory = await getApplicationDocumentsDirectory();
  String path = directory.path;
  flog(path); // /data/user/0/com.bqt.flutter.flutter_app_test/app_flutter

  File file = File('$path/content.txt'); // 创建文件

  List<String> formats = ['bqt ', yyyy, '-', mm, '-', dd, ' ', HH, ':', nn, ':', ss, '\n'];
  String content = formatDate(DateTime.now(), formats);
  file.writeAsString(content, mode: FileMode.append); // 将字符串写入文件

  String text = await file.readAsString(); // 从文件读出字符串
  flog(text);
}

除了字符串读写之外,Flutter 还提供了二进制流的读写能力,可以支持图片、压缩包等二进制文件的读写。

SharedPreferences

需要引入 shared_preferences

SharedPreferences 会以原生平台相关的机制,为简单的键值对数据提供持久化存储,即在 iOS 上使用 NSUserDefaults,在 Android 使用 SharedPreferences

SharedPreferences 只能存储基本类型的数据,比如 int、double、bool 和 string。

void testSP() async {
  // 由于涉及到耗时的文件读写,需要在异步环境下进行
  SharedPreferences sp = await SharedPreferences.getInstance();
  int counter = (sp.getInt('counter') ?? 0);
  sp.setInt('counter', ++counter);
  flog("${sp.getInt('counter')}");
}

注意:setter 方法会同步更新内存中的键值对,然后将数据保存至磁盘

数据库 sqflite

需要引入 sqflite

SharedPrefernces 只适用于持久化少量数据的场景,如果需要持久化大量格式化后的数据,并且这些数据还会以较高的频率更新,通常会选用 sqlite 数据库。

dbDemo() async {
  // 创建数据库
  String createSql = "CREATE TABLE students(id TEXT PRIMARY KEY, name TEXT, score INTEGER)";
  Future<Database> database = openDatabase(
    // join 方法需要手动导包 import 'package:path/path.dart';
    join(await getDatabasesPath(), 'students_database.db'),
    onCreate: (db, version) => db.execute(createSql),
    onUpgrade: (db, oldVersion, newVersion) => flog("old:$oldVersion, new:$newVersion"),
    version: 1,
  );

  Database db = await database;
  await db.insert(
    'students',
    HashMap(), // 插入数据
    conflictAlgorithm: ConflictAlgorithm.replace, // 插入冲突策略:新的替换旧的
  );

  List<Map<String, dynamic>> maps = await db.query('students'); // 批量查询数据

  db.close(); // 释放数据库资源
}
  • 使用 join 方法对两段地址进行拼接时,会使用操作系统的路径分隔符
  • 调用 openDatabase 创建数据库时传入的 version,和在 onCreate 中回调的 version 是相等的
  • 数据库只会创建一次,所以 onCreate 方法在应用从安装到卸载的生命周期中,只会执行一次
  • 如果想对数据库的存储字段进行改动,可以根据 onUpgrade 中的 oldVersion 和 newVersion 确定升级策略
    • oldVersion 代表用户手机上的数据库版本
    • newVersion 代表当前版本的数据库版本
    • 用户的升级顺序并不总是连续的,因此需要在 onUpgrade 中制定合适的升级方案
  • 插入冲突策略:如果同样的对象被插入两次,则后者替换前者
  • 查询的时候可以采用批量读的方式,也可以指定查询规则读特定对象

除了基础的数据库读写操作之外,sqlite 还提供了更新、删除以及事务等高级特性,这与原生 Android、iOS 上的 SQLite 或是 MySQL 并无不同。

2023-3-9

posted @ 2023-03-09 00:45  白乾涛  阅读(282)  评论(1编辑  收藏  举报