应用后保留 SQFlite 数据的最佳方法是 uninstalled/reinstalled on Android?

Best way to keep SQFlite data after app is uninstalled/reinstalled on Android?

我的 SQFlite 有问题,应用程序 uninstalled/reinstalled 后数据库被删除。我的客户将在数据库中存储数千条日志,我不能冒数据丢失的风险。

我的一些问题和想法:

我可以在外部文件系统中创建 SQFLite 数据库文件并直接从那里的 db 文件查询吗?

或者我唯一的选择是不断将 db 文件的副本作为备份写入外部文件系统?如果文件大小达到 2-5mb,这会成为问题吗?写入速度会很慢还是会导致崩溃?

我是否应该完全跳过使用 SQFlite 并使用远程 SQL 服务器数据库来代替我的目的?

我觉得很烦人,因为似乎没有备份 SQFLite 的好选择。我敢肯定,许多应用程序都需要保留数据。

谢谢!

从一开始就使用 Firebase 之类的东西。不要存储在本地。

您可以通过将 SQFLite 数据库存储在外部存储器中来保留应用程序安装之间的数据,因为卸载应用程序时不会删除这些数据。我自己测试过,确实有效。

以下是如何在外部存储器中设置该数据库的示例:

import 'dart:io';
import 'package:SQFLite_test/helpers/ClientMocker.dart';
import 'package:SQFLite_test/models/ClientModel.dart';
import 'package:ext_storage/ext_storage.dart';
import 'package:flutter/cupertino.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:sqflite/sqflite.dart';

class LogServiceTwo {
  LogServiceTwo._();

  static final LogServiceTwo logRepo = LogServiceTwo._();

  static Database _database;

  Future<Database> get database async {
    if (_database != null) {
      return _database;
    }

    await askForWritePermission();
    var db = await openDb();
    if (db == null) {
      _database = await initDB();
      return _database;
    }

    var hasClientTableB = await hasClientTable(db);
    if (hasClientTableB) {
      _database = db;
      return _database;
    }

    await createClientTable(db);
    _database = db;
    return _database;
  }

  Future createClientTable(Database db) async {
    await db.execute("CREATE TABLE Client ("
        "id INTEGER PRIMARY KEY,"
        "first_name TEXT,"
        "last_name TEXT,"
        "blocked BIT"
        ")");
  }

  Future<bool> hasClientTable(Database db) async {
    try {
      var table = await db.query("Client");
      return table != null;
    } catch (e) {
      return false;
    }
  }

  Future<Database> openDb() async {
    try {
      var path = await getPersistentDbPath();
      var db = await openDatabase(path, version: 1);
      return db;
    } catch (e) {
      return null;
    }
  }

  Future initDB() async {
    var path = await getPersistentDbPath();
    return await openDatabase(path, version: 1, onOpen: (db) {}, onCreate: (Database db, int version) async {
      await db.execute("CREATE TABLE Client ("
          "id INTEGER PRIMARY KEY,"
          "first_name TEXT,"
          "last_name TEXT,"
          "blocked BIT"
          ")");
    });
  }

  Future newClient(Client newClient) async {
    final db = await database;
    var res = await db.insert("Client", newClient.toMap());
    return res;
  }

  Future newClients(List<Client> clients) async {
    var clientMaps = clients.map((client) => client.toMap()).toList();
    final db = await database;
    var batch = db.batch();
    clientMaps.forEach((clientMap) async {
      batch.insert("Client", clientMap);
    });
    await batch.commit(noResult: true);
  }

  Future<Client> getClient(int id) async {
    final db = await database;
    var res = await db.query("Client", where: "id = ?", whereArgs: [id]);
    return res.isNotEmpty ? Client.fromMap(res.first) : Null;
  }

  Future<List<Client>> getAllClients() async {
    final db = await database;
    var res = await db.query("Client");
    List<Client> list = res.isNotEmpty ? res.map((c) => Client.fromMap(c)).toList() : [];
    return list;
  }

  Future<List<Client>> getBlockedClients() async {
    final db = await logRepo.database;
    var res = await db.rawQuery("SELECT * FROM Client WHERE blocked=1");
    List<Client> list = res.isNotEmpty ? res.toList().map((c) => Client.fromMap(c)) : null;
    return list;
  }

  Future<List<String>> getTables() async {
    var db = await logRepo.database;
    var tableNames = (await db.query('sqlite_master', where: 'type = ?', whereArgs: ['table'])).map((row) => row['name'] as String).toList(growable: false);
    return tableNames;
  }

  Future<String> getPersistentDbPath() async {
    return await createPersistentDbDirecotry();
  }

  Future<String> createPersistentDbDirecotry() async {
    var externalDirectoryPath = await ExtStorage.getExternalStorageDirectory();
    var persistentDirectory = "$externalDirectoryPath/db_persistent";
    var directory = await createDirectory(persistentDirectory);
    listFiles(directory);
    return "$persistentDirectory/persistent.db";
  }

  listFiles(Directory directory) {
    print("${directory.path} files:");
    directory.list().forEach((file) {
      print(file.path);
      print(file.statSync().size);
    });
  }

  Future<Directory> createDirectory(String path) async {
    return await (new Directory(path).create());
  }

  Future<bool> askForWritePermission() async {
    var status = await Permission.storage.status;
    if (!status.isGranted) {
      status = await Permission.storage.request();
      return status.isGranted;
    }
    return status.isGranted;
  }

  Future mockData() async {
    var clients = ClientMocker.createClients();
    await newClients(clients);
  }

  Future deleteAll() async {
    var db = await database;
    await db.rawDelete("DELETE FROM Client");
  }

  Future getClients() async {
    try {
      var db = await database;
      return await db.rawQuery("SELECT * FROM Client");
    } catch (e) {
      print(e);
    }
  }
}