Flutter sqflite-从资产加载数据库时出现问题

时间:2020-05-18 00:40:39

标签: flutter sqflite

我正在使用以下代码从资产复制数据库。大多数时候,此代码都能正常工作。但是,在将我的应用发布到应用商店后,我收到了一些用户的投诉,导致数据库无法加载。然后,我尝试用自己的iPhone卸载并再次从应用商店下载该应用。奇怪的是安装了大约10次,数据库加载失败是1次。这是我的数据库助手:

class DatabaseHelper {
  static const NEW_DB_VERSION = 6;

  static final DatabaseHelper _instance = DatabaseHelper.internal();

  factory DatabaseHelper() => _instance;

  DatabaseHelper.internal();

  Database _db;

  Future<Database> get db async {
    if (_db != null) {
      return _db;
    } else {
      _db = await initDb();
      return _db;
    }
  }

  Future<Database> initDb() async {

    final databasesPath = await getDatabasesPath();
    final path = join(databasesPath, "dictionary");

    var db = await openDatabase(path);

    //if database does not exist yet it will return version 0
    if (await db.getVersion() < NEW_DB_VERSION) {
      db.close();

      try {
        await Directory(dirname(path)).create(recursive: true);
      } catch (_) {}

      //copy db from assets to database folder
      ByteData data = await rootBundle.load("assets/dictionary");
      List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
      await File(path).writeAsBytes(bytes, flush: true);

      //open the newly created db
      db = await openDatabase(path);

      //set the new version to the copied db so you do not need to do it manually on your bundled database.db
      db.setVersion(NEW_DB_VERSION);

    }

    return db;
  }
}

我通过使用

在我的主要活动中初始化数据库
DatabaseHelper db = DatabaseHelper();

为什么这个奇怪的问题发生了?

1 个答案:

答案 0 :(得分:1)

如果多次调用db / initDb(可能在您的代码中发生),则可能会发生某些竞态条件,这可能会带来一些无法预测的结果。

我宁愿将您的initDb设为私有,并确保不会多次调用它,例如:

import 'package:sqflite_common/sqlite_api.dart';
import 'package:synchronized/synchronized.dart';

class OpenHelper {
  Database _db;

  final _dbLock = Lock();

  Future<Database> get db async {
    if (_db != null) {
      return _db;
    } else {
      // Safe guard _initDb so that it is ran only once
      await _dbLock.synchronized(() async {
        // Don't call it if _db is defined.
        _db ??= await _initDb();
      });
      return _db;
    }
  }
}

或更简单(但不存储数据库引用,只是将来):

import 'package:sqflite_common/sqlite_api.dart';

class OpenHelper {
  Future<Database> _db;

  Future<Database> get db {
    _db ??= _initDb();
    return _db;
}

然后查看是否可以解决问题。