更新预填充数据库

2023-12-09

我为 Android 设备创建了一个问答游戏。我有一个数据库,在资产文件夹和 dbHelper 类中存在问题。一切正常,但现在我想修复一些拼写错误并添加更多问题。我需要更新数据库,但我不知道该怎么做。我在互联网上找到了这个 dbHelper 类,但我自己没有足够的知识。我知道我应该比较新数据库和现有数据库的版本,如果它们不匹配,我需要删除旧数据库并安装新数据库。

onUpgrade 方法为空

class dbHelper extends SQLiteOpenHelper {


    private static final String DATABASE_NAME = "questions.db";
    private  static final int SCHEMA_VERSION = 1;

    public SQLiteDatabase dbSglite;
    private String mDBPath;

    private final Context myContext;

    public dbHelper(Context context) {
        super(context, DATABASE_NAME, null, SCHEMA_VERSION);
        this.myContext=context;
        this.mDBPath=context.getDatabasePath(DATABASE_NAME).getParent();
    }

    @Override
    public void onCreate(SQLiteDatabase db){
        Log.d("ONCREATE","OnCreate Method Called.");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    public void createDatabase(){
        createDB();
    }

    private void createDB(){

        boolean dbExist = DBExists();

        if(!dbExist){
            //this.getReadableDatabase();
            copyDBFromResource();

        }

        dbSglite=getReadableDatabase();
    }

    private boolean DBExists(){

        SQLiteDatabase db = null;

        try {
            String databasePath = myContext.getDatabasePath(DATABASE_NAME).getPath();
            db = SQLiteDatabase.openDatabase(databasePath,null, SQLiteDatabase.OPEN_READWRITE);
            db.setLocale(Locale.getDefault());
            db.setLockingEnabled(true);
            db.setVersion(1);
        } catch (SQLiteException e) {

            Log.e("SqlHelper", "database not found");
        }

        if (db != null) {
            db.close();
        }
        return db != null;

    }

    private void copyDBFromResource() {
        InputStream inputStream = null;
        OutputStream outputStream = null;

        try {
            inputStream = myContext.getAssets().open(DATABASE_NAME);
            File databasedir = new File(myContext.getDatabasePath(DATABASE_NAME).getParent());
            databasedir.mkdirs();
            outputStream = new FileOutputStream(mDBPath+"/"+DATABASE_NAME);
            byte[] buffer = new byte[1024];
            int length;
            while ((length=inputStream.read(buffer))>0){
                outputStream.write(buffer, 0, length);
            }

            outputStream.flush();
            outputStream.close();
            inputStream.close();

        } catch (IOException e) {
            e.printStackTrace();
            throw new Error("Problem copying database.");
        }

    }

    public void openDataBase() throws SQLException {

        String myPath = myContext.getDatabasePath(DATABASE_NAME).getPath();
        dbSglite = SQLiteDatabase.openDatabase(myPath, null,
                SQLiteDatabase.OPEN_READWRITE);

    }

}

根据 Gabe Sechan 的评论,最简单的方法是每次启动应用程序时从资产文件夹中复制数据库,即更改:-

private void createDB(){
    boolean dbExist = DBExists();

    if(!dbExist){
        this.getReadableDatabase();
        copyDBFromResource();

    }
    dbSglite=getReadableDatabase();
}

to :-

private void createDB(){
    copyDBFromResource();
    dbSglite=getReadableDatabase();
}

您显然对评论有疑虑

“那不是每次活动启动时都会复制数据库吗?”

是的,会的(那会那么糟糕吗?-修辞的).


但是,假设您要使用数据库版本,即根据当前版本检查资产文件夹中的版本。您基本上仍然需要从资产文件夹访问数据库,因此您将对照另一个数据库检查一个数据库(至少打开它们)。所以仍然会有一些开销。

一个可能不太密集的选项是检查资产文件的上一次更改日期与共享首选项中最后复制的资产文件的日期相对应。 (File lastModified方法)文件 - 上次修改时间.

从类似的角度来看,另一个选择是检查包version针对最后实施的,再次存储在共享首选项中。包信息 - 版本代码.

当然,在这两个选项中,仅当存在差异(增加)时才会从资产文件中替换数据库。


使用包版本的示例

以下示例(在dbHelper如果包版本增加(或者数据库不存在),类)将从资产中复制数据库:-

class dbHelper extends SQLiteOpenHelper {


    private static final String DATABASE_NAME = "questions.db";
    private  static final int SCHEMA_VERSION = 1;
    private static  final String SHARED_PREFS = "shared_prefs";
    private static final String SHARED_PREFKEY_QUESTIONSDBLASTUPDATED = "spkey_qdblastupdated";

    public SQLiteDatabase dbSglite;
    private String mDBPath;

    private final Context myContext;

    public dbHelper(Context context) {
        super(context, DATABASE_NAME, null, SCHEMA_VERSION);
        this.myContext=context;
        this.mDBPath=context.getDatabasePath(DATABASE_NAME).getParent();
    }

    @Override
    public void onCreate(SQLiteDatabase db){
        Log.d("ONCREATE","OnCreate Method Called.");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    public void createDatabase(){
        createDB();
    }

    private void createDB(){

        if (isQuestionsDBNew() || (!DBExists())) {
            Log.d("COPYFROMASSET", "Copying Questions From Assets");
            copyDBFromResource();
            setQuestionsDBNew(getPackageVersion());
        } else {
            Log.d("COPYFROMASSET",
                    "Questions not copied from Assets - New Questions Check result was " +
                            Boolean.toString(isQuestionsDBNew()) +
                            " DB Exists result was " + Boolean.toString(DBExists())
            );
        }
        dbSglite=getReadableDatabase();
    }

    private boolean DBExists(){

        SQLiteDatabase db = null;

        try {
            String databasePath = myContext.getDatabasePath(DATABASE_NAME).getPath();
            db = SQLiteDatabase.openDatabase(databasePath,null, SQLiteDatabase.OPEN_READWRITE);
            db.setLocale(Locale.getDefault());
            db.setLockingEnabled(true);
            db.setVersion(1);
        } catch (SQLiteException e) {

            Log.e("SqlHelper", "database not found");
        }

        if (db != null) {
            db.close();
        }
        return db != null;

    }

    private void copyDBFromResource() {
        InputStream inputStream = null;
        OutputStream outputStream = null;

        try {
            inputStream = myContext.getAssets().open(DATABASE_NAME);
            File databasedir = new File(myContext.getDatabasePath(DATABASE_NAME).getParent());
            databasedir.mkdirs();
            outputStream = new FileOutputStream(mDBPath+"/"+DATABASE_NAME);
            byte[] buffer = new byte[1024];
            int length;
            while ((length=inputStream.read(buffer))>0){
                outputStream.write(buffer, 0, length);
            }

            outputStream.flush();
            outputStream.close();
            inputStream.close();

        } catch (IOException e) {
            e.printStackTrace();
            throw new Error("Problem copying database.");
        }

    }

    public void openDataBase() throws SQLException {
        String myPath = myContext.getDatabasePath(DATABASE_NAME).getPath();
        dbSglite = SQLiteDatabase.openDatabase(myPath, null,
                SQLiteDatabase.OPEN_READWRITE);

    }

    private boolean isQuestionsDBNew() {
        SharedPreferences prefs = myContext.getSharedPreferences(SHARED_PREFS, Context.MODE_PRIVATE);
        long stored_lastused = prefs.getLong(SHARED_PREFKEY_QUESTIONSDBLASTUPDATED,-1);
        Log.d("NEWQUESTIONS?", "Result of testing package version " +
                String.valueOf(stored_lastused) +
                " against " +
                String.valueOf( getPackageVersion()) +
                " was " + String.valueOf(stored_lastused < getPackageVersion()));
        return  (stored_lastused < getPackageVersion());
    }

    private long getPackageVersion() {
        PackageInfo pi;
        try {
            pi = myContext.getPackageManager().getPackageInfo(myContext.getPackageName(),0);
        } catch (PackageManager.NameNotFoundException e) {
            return -1;
        }
        Log.d("PACKAGEVERSION", "The version of package " +
                myContext.getPackageName() +
                " was " +
                String.valueOf(pi.versionCode)
        );
        return pi.versionCode;
    }

    private void setQuestionsDBNew(long lastused) {
        SharedPreferences.Editor editor = myContext.getSharedPreferences(SHARED_PREFS, Context.MODE_PRIVATE).edit();
        editor.putLong(SHARED_PREFKEY_QUESTIONSDBLASTUPDATED,lastused);
        editor.apply();
    }
}

Notes

  • The code is very much based upon the code from the question. There are :-
    • 用于共享首选项处理的两个附加类变量(常量)。
    • 三种新方法:-
    • isQuestionsDBNew如果包版本大于共享首选项中存储的版本,则返回 true(共享首选项中没有任何内容会导致 -1,因此应该小于任何包版本)。
    • getPackageVersion返回长整型包版本。
    • setQuestionsDBNew这会更新适用的共享首选项。
    • 更改 createDB 以检查包版本更改,然后从资产复制数据库。还有一个额外的检查来查看数据库是否存在,尽管只有在删除数据库文件时才需要这样做。删除应用程序的数据将删除共享首选项,从而导致数据库被复制。
  • 该代码包括我留下的一些诊断日志记录。
  • 这还没有经过广泛的测试(即我还没有达到增加软件包版本的程度)。

示例的输出 - 正在安装的应用程序:-

01-05 19:46:44.849 26692-26692/m.com.so48103235_updateprepopdb D/PACKAGEVERSION: The version of package m.com.so48103235_updateprepopdb was 1
01-05 19:46:44.850 26692-26692/m.com.so48103235_updateprepopdb D/PACKAGEVERSION: The version of package m.com.so48103235_updateprepopdb was 1
01-05 19:46:44.850 26692-26692/m.com.so48103235_updateprepopdb D/NEWQUESTIONS?: Result of testing package version -1 against 1 was true
01-05 19:46:44.850 26692-26692/m.com.so48103235_updateprepopdb D/PACKAGEVERSION: The version of package m.com.so48103235_updateprepopdb was 1
01-05 19:46:44.850 26692-26692/m.com.so48103235_updateprepopdb D/COPYFROMASSET: Copying Questions From Assets
01-05 19:46:44.855 26692-26692/m.com.so48103235_updateprepopdb D/PACKAGEVERSION: The version of package m.com.so48103235_updateprepopdb was 1

示例的输出 - 后续运行:-

01-05 19:48:10.375 26755-26755/m.com.so48103235_updateprepopdb D/PACKAGEVERSION: The version of package m.com.so48103235_updateprepopdb was 1
01-05 19:48:10.376 26755-26755/m.com.so48103235_updateprepopdb D/PACKAGEVERSION: The version of package m.com.so48103235_updateprepopdb was 1
01-05 19:48:10.376 26755-26755/m.com.so48103235_updateprepopdb D/NEWQUESTIONS?: Result of testing package version 1 against 1 was false
01-05 19:48:10.376 26755-26755/m.com.so48103235_updateprepopdb D/PACKAGEVERSION: The version of package m.com.so48103235_updateprepopdb was 1
01-05 19:48:10.381 26755-26755/m.com.so48103235_updateprepopdb D/PACKAGEVERSION: The version of package m.com.so48103235_updateprepopdb was 1
01-05 19:48:10.381 26755-26755/m.com.so48103235_updateprepopdb D/PACKAGEVERSION: The version of package m.com.so48103235_updateprepopdb was 1
01-05 19:48:10.381 26755-26755/m.com.so48103235_updateprepopdb D/NEWQUESTIONS?: Result of testing package version 1 against 1 was false
01-05 19:48:10.382 26755-26755/m.com.so48103235_updateprepopdb D/PACKAGEVERSION: The version of package m.com.so48103235_updateprepopdb was 1
01-05 19:48:10.387 26755-26755/m.com.so48103235_updateprepopdb D/COPYFROMASSET: Questions not copied from Assets - New Questions Check result was false DB Exists result was true
  • 由于报告数据库未复制而再次调用添加日志消息的方法时使用了更广泛的消息,因此产生了额外的消息。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

更新预填充数据库 的相关文章

  • 如何自定义菜单项的背景颜色?

    我正在尝试定制Toolbar的弹出菜单 现在我无法设置菜单项的背景颜色 我的 styles xml 如下所示
  • Android短音的正确播放方法?

    我正在创建一个应用程序 屏幕上将有多个图像 这些图像将是按钮 点击时会播放短促的声音 我对此进行了研究 只能找到我当前用来播放声音的方法 这似乎根本没有响应 我希望声音能够快速播放并且能够响应多次快速点击 我不确定这在 Android 中是
  • 如何正确释放Android MediaPlayer

    我正在尝试向我的 Android 应用程序添加一个按钮 当点击该按钮时它会播放 MP3 我已经让它工作了 但没有办法释放 mediaPlayer 对象 因此即使在我离开活动后它仍然会继续播放 如果我在react 方法之外初始化MediaPl
  • 按下按钮时应用不同的样式

    有没有办法在按下按钮时将样式应用于按钮 如果我有一种风格样式 xml
  • 如何在 Linux 内核中定义并触发我自己的新软中断?

    我想在 Linux 内核中创建自己的软中断 这是正确的方法吗 In the init我想触发该模块的softirq我将添加一个调用 394 void open softirq int nr void action struct softir
  • Bitmap.getPixels() 中的 IllegalArgumentException

    我想将数据从位图复制到int using getPixels 这是我当前的代码 int pixels new int myBitmap getHeight myBitmap getWidth myBitmap getPixels pixel
  • OnUpgrade SQFLITE:未处理的异常:DatabaseException(表 UsernameTable 没有名为 RememberMe 的列(Sqlite 代码 1):

    未处理的异常 DatabaseException 表 UsernameTable 没有 名为 RememberMe 的列 Sqlite 代码 1 编译时 INSERT OR 替换为 UsernameTable 用户名 rememberMe
  • 以编程方式将文本颜色设置为主要 Android 文本视图

    如何设置我的文本颜色TextView to android textColorPrimary以编程方式 我已经尝试了下面的代码 但它将 textColorPrimary 和 textColorPrimary Inverse 的文本颜色始终设
  • 在 Cordova 应用程序中获取额外功能

    我们有两个 Android 应用程序 一个使用本机 Java 实现 另一个使用 Ionic 编写 Ionic 应用程序启动我的应用程序 这是使用灯插件 https github com lampaa com lampa startapp 我
  • ExoPlayer2 - 如何使 HTTP 301 重定向工作?

    我开始使用 ExoPlayer 来传输一些音频 一切都很顺利 直到我遇到一个带有 301 永久移动 重定向的 URL ExoPlayer2 默认情况下不处理该问题 我已经看过这个线程 https github com google ExoP
  • Android 手机作为 GSM 调制解调器在 PC 上发送/接收短信?

    是否可以将 Android 移动设备用作 PC 上的 GSM 调制解调器 我正在 net下开发应用程序来发送 接收短信等 现在我想通过 USB 将我的 Android 设备连接到我的 PC 并将其用作 GSM 调制解调器来与其通信 这里是参
  • Android Studio 与本地网络共享上的项目文件

    这是我的设置 Android Studio 项目文件位于 Ubuntu 14 10 盒子上的共享文件夹中 尝试在 Windows 8 机器上运行 Android Studio 1 0 2 并将 U 驱动器映射到包含项目文件的 Ubuntu
  • 当 OnFocusChangeListener 应用于包装的 EditText 时,TextInputLayout 没有动画

    不能比标题说得更清楚了 我有一个由文本输入布局包裹的 EditText 我试图在 EditText 失去焦点时触发一个事件 但是 一旦应用了事件侦听器 TextInputLayout 就不再对文本进行动画处理 它只是位于 editText
  • 使用 AsyncTask 传递值

    我一直在努力解决这个问题 但我已经到了不知道该怎么办的地步 我想做的是使用一个类下载文件并将其解析为字符串 然后将该字符串发送到另一个类来解析 JSON 内容 所有部件都可以单独工作 并且我已经单独测试了所有部件 我只是不知道如何将值发送到
  • 我应该释放或重置 MediaPlayer 吗?

    我有自己的自定义适配器类 称为 WordAdapter 并且我正在使用媒体播放器 名为pronounce WordAdapter 类中的全局变量 我有不同的活动 其中每个列表项都有线性布局 名为linearLayout 我正在设置onCli
  • 插件“Android Bundle Support”不兼容

    大家好 自从上次更新以来 当我启动 android studio 时 我遇到了一个非常奇怪的错误 我有这个错误 插件错误 插件 Android Bundle Support 不兼容 直到构建 AI 195 SNAPSHOT 我在网上找不到任
  • Android:如何从网络异步获取搜索建议?

    我创建了一个可搜索的活动 现在 我想添加从网络服务获取的搜索建议 我想异步获取这些建议 根据添加自定义建议 http developer android com guide topics search adding custom sugge
  • SQLite-Net 扩展 - GetAllWithChildrenAsync 未提取所有内容

    我正在尝试使用 SQLite Net 扩展来创建关系数据库 我在尝试从数据库中提取 Term 对象时遇到了问题 它成功地撤回了其关联的课程 但未撤回与课程关联的评估和笔记 我不确定问题是否在于如何将对象插入数据库 如何从数据库中提取对象 或
  • Android 后台倒计时器

    我有一个 Android 应用程序 它管理一个倒计时器 类 CountDownTimer 它显示在应用程序屏幕中 以显示到达 00 00 还剩多少时间 我现在的问题是 当我按主页按钮或启动另一个应用程序时 应用程序 计时器不会在后台运行 所
  • Git 实验分支还是单独的实验存储库?

    我正在开发一个 Android 应用程序 并且在整个开发周期中一直使用 Git 现在 我想构建并发布实验性功能 供人们尝试和安装 同时仍将原始的 稳定的应用程序安装在他们的设备上 现在 这意味着我需要使用不同的包名称 这会更改开发项目中的一

随机推荐

  • 查找组中最常见的观察结果[重复]

    这个问题在这里已经有答案了 数据框 B pd DataFrame b II II II II II I I I MOST FREQUENT 1 2 2 1 1 1 2 2 我需要获取列中出现次数最多的值MOST FREQUENT对于每组 p
  • #[inline] 可以在特征方法声明和实现中使用吗?

    我有一些小方法的特征 这些方法通常作为实现结构所具有的其他方法的单行包装器来实现 如果我想确保特征方法是内联的 我应该放置 inline always 在特征定义内 或在impl对于每个结构 我更愿意简单地将其放入特征定义中 但据我所知 这
  • 如何将最新更改拉取到 GitHub 中我当前的工作分支?

    假设我在分支 abc test git pull origin master 这是否会将 master 分支与我当前的分支 abc test 合并 或者我是否需要运行更多命令 tl dr run git fetch获取最新更改 然后运行gi
  • 在 2.0.5 中,将 cassandra 作为服务启动不起作用,sudo cassandra -f 有效

    当我尝试在 ubuntu 12 04 上启动 cassandra 时 通过 Datastax 安装 dsc20包 作为服务如下 sudo 服务 cassandra 启动 it says 无法访问 Cassandra 的 pidfile 日志
  • 如何使用弹出窗口在 JavaScript 中构建一个简单的图片库

    我在互联网上寻找帮助 但我无法让它工作 有人能给我一个如何编写这样的代码的例子吗 我会调整图像的大小 并为弹出窗口提供一个缩略图大小的图像和一个更大的图像 我希望用户单击缩略图大小的图像并在弹出窗口中显示全尺寸的图像 我是 Javascri
  • Excel:如何使用VBA检查单元格是否为空? [复制]

    这个问题在这里已经有答案了 通过VBA 我如何检查一个单元格是否是另一个具有特定信息的空单元格 例如 如果 A A 产品特殊 且 B B 为 null 那么 C1 产品特殊 另外 我如何使用For Each循环在Range以及如何返回另一个
  • 选择不同数据库中的列

    是否可以在位于同一服务器上的不同数据库之间执行选择 或插入 语句 如果是 怎么办 您可以使用以下语法指定数据库databasename tablename Example SELECT mydatabase1 tblUsers UserID
  • 如何彻底卸载oracle 11g?

    如何从笔记本电脑上卸载 Oracle 11g 软件附带的卸载程序并不能完全卸载所有组件 我用Oracle12c试了一下 留下了很多程序 我尝试手动删除这些文件 但 BIN 目录中的某些 dll 文件无法访问 我想用 11g 做正确的事 有什
  • 使用jquery从父页面访问子IFrame中的元素

    我尝试使用以下代码从父文档访问 iframe 中文档的元素 但由于某种原因无法使其工作 父级 html
  • 需要帮助使用 GIOService(GLib、Glib-GIO)实现简单的套接字服务器

    我正在学习使用 GLib 编写简单 高效的套接字服务器的基础知识 我正在尝试 GSocketService 到目前为止 我似乎只能接受连接 但随后它们立即关闭 从文档中我无法弄清楚我错过了哪一步 我希望有人能为我阐明这一点 运行以下命令时
  • 如何提高最低成本路径模型的模拟速度

    通过使用网络扩展 以下代码在两个多边形 由多个面片组成 之间构建成本最低的路径 to calculate LCP ID polygon 1 ID polygon 2 let path let path cost 1 Define polyg
  • 如何确定用户在汇编语言 X86 中输入的字符串中单词的频率?

    我是汇编语言编程的完全初学者 我需要帮助编写一个汇编语言程序来从用户那里获取字符串 计算并显示每个单词在用户输入的字符串中出现的次数 例如 如果用户输入 Hello Hello what is new Hello what is not n
  • 查找数组一中最接近数组二的元素

    这个答案解释如何找到最接近 已排序 的数组元素单点 以对大型数组有效的方式 稍作修改 def arg nearest array value idx np searchsorted array value side left if idx
  • 如何使用 XAML 绑定按钮单击来更改面板(网格)的内容

    我正在创建 WPF 应用程序的 UI 在致力于软件功能的实现时 我在创建 UI 方面没有太多经验 现在我需要一种方法来更改 属性 面板的内容 该面板有一个网格来包含内容 我创建了多个面板 隐藏了除一个之外的所有面板 现在我想在用户单击顶部功
  • Slim PHP 的默认 GET 路由

    我最近使用 Slim PHP 框架构建了一个小型 API 它运行得很好 然而 我想为根 设置一个 GET 路由 它以基本消息响应 并让任何其他 GET 请求返回 访问被拒绝 在阅读了文档和各种示例后 我无法弄清楚如何完成这些任务 我的项目仅
  • APC 3.1.x 的稳定性如何?

    是否有人在大容量站点的生产中使用 APC 3 1 x 3 1 系列被标记为 测试版 版本 但它具有我们真正希望拥有的一些功能 具体来说 apc clear cache user 的性能改进没有成为 3 0 19 那么 您是否在非常活跃的站点
  • Python - 根据列的最大值删除重复项

    我不太擅长使用 pandas 我认为 pandas 应该解决我的问题 我有一个文本文件 其中包含数据 id1 id2 value1 value2 value3 1 2 30 40 20 3 1 2 30 42 26 2 3 5 12 55
  • 从 NTFS-MFT 参考号获取文件信息

    在我的 C 应用程序中 我已经有一种方法来检查文件系统 但我想利用从主文件表 MFT 中读取数据的优势 因为它的速度要快得多 我了解 1 它是专有规范 因此如有更改 恕不另行通知 2 仅当应用程序在管理权限下运行时才能访问它 我设法通过读取
  • 在 xpath/domdocument 查询中查找与给定字符串匹配的链接

    使用 Xpath 和 domDocument 获取与给定单词匹配的链接进行显示时遇到问题 一切似乎都进展顺利for i 0 i lt documentLinks gt length i 用来 谁能帮我解决我哪里出错了 html ol htm
  • 更新预填充数据库

    我为 Android 设备创建了一个问答游戏 我有一个数据库 在资产文件夹和 dbHelper 类中存在问题 一切正常 但现在我想修复一些拼写错误并添加更多问题 我需要更新数据库 但我不知道该怎么做 我在互联网上找到了这个 dbHelper