繁体   English   中英

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

[英]Flutter sqflite - Problem loading database from asset

我正在使用以下代码从资产中复制数据库。 大多数时候,这段代码工作正常。 但是,在我的应用发布到应用商店后,我收到了一些用户的抱怨,称数据库无法加载。 然后我在自己的 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();

为什么会出现这个奇怪的问题?

如果 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;
}

看看这是否能解决问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM