更新预先填充的数据库 [英] Updating a prepopulated database

查看:82
本文介绍了更新预先填充的数据库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我为android设备创建了一个琐事测验.我有一个资产文件夹和dbHelper类中有问题的数据库.一切正常,但现在我想修复一些错字并添加更多问题.我需要更新数据库,但是我不知道该怎么做.我在Internet上找到了这个dbHelper类,而我自己对此没有足够的知识.我知道我应该比较新数据库和现有数据库的版本,如果它们不匹配,我需要删除旧数据库并安装新数据库.

I have created a trivia quiz for android devices. I have a database with questions in assets folder and dbHelper class. Everything works fine, but now i want to fix some typos and add more questions. I need to update database, but i don't know how to do that. I found this dbHelper class on the Internet and i don't have enough knowledge to to this by myself. I understand that I should compare versions of new database and existing database and if they don't match I need to remove old database and install new one.

onUpgrade方法为空

onUpgrade method is empty

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的评论,最简单的方法是每次启动应用程序时从资产文件夹复制db,即进行更改: -

As per the comment from Gabe Sechan, the simplest method would be to copy the db from the assets folder every time the App is started, that is to change :-

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

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

    }
    dbSglite=getReadableDatabase();
}

至:-

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

您显然担心要发表评论

每次启动活动时都不会复制数据库."

"Wouldn't that copy DB every time activity is started."

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

yes it would (would that be that bad? - rhetorical).

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

However, say you were to utilise the Database Version i.e. check the version in the assets folder against the current version. You still basically need to access the database from the assets folder, so you would be checking one database against another (at least opening them). So there would still be some overheads.

一个可能不太密集的选项是,将资产文件的上次修改日期与共享首选项中最后复制的资产文件的日期进行比较. (File lastModified方法)文件-lastModified .

An option that may be less intensive would be check the asset file's last modified date against a the date of the last copied asset file in shared preferences. (File lastModified method) File - lastModified.

在类似的视图中,另一种选择是将软件包版本与最后实现的软件包进行比较,并再次存储在共享的首选项中.

Another option, in a similar view, would be to check the package version against the last implemented, again stored in shared preferences.PackageInfo - versionCode.

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

Of course in both these options, replacing the database from the assets file only happening when there is a difference (increase).

下面的示例( dbHelper 类中的所有更改)将从软件包中复制数据库,如果增加了软件包版本(或者如果数据库不存在):-

The following example (all changes within the dbHelper class) will copy the Database from the assets if the package version is increased (or if the Database doesn't exist) :-

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();
    }
}

注释

  • 代码很大程度上基于问题中的代码.有 :-
    • 另外两个用于共享首选项处理的类变量(常量).
    • 三种新方法:-
    • isQuestionsDBNew,如果程序包版本大于共享首选项中的版本存储(共享首选项中的任何内容都不为-1,则应小于任何程序包版本),则返回true.
    • getPackageVersion返回软件包的版本号.
    • setQuestionsDBNew会更新适用的共享首选项.
    • 更改为createDB以检查软件包版本更改,然后从资产中复制数据库.尽管仅当删除了数据库文件时才需要检查数据库,但还需要进行其他检查.删除应用程序的数据将删除共享的首选项,因此将导致数据库被复制.
    • Notes

      • The code is very much based upon the code from the question. There are :-
        • Two additional class variables (constants) for the shared preferences handling.
        • Three new methods :-
        • isQuestionsDBNew that returns true if the package version is greater than the version store in shared preferences (nothing in shared preferences results in -1, so should be less than any package version).
        • getPackageVersion returns the package version as a long.
        • setQuestionsDBNew which updates the applicable shared preference.
        • Changes to the createDB to check for the package version change and to then copy the database from the assets. There is an additional check to see if the database exists, although this would only be needed if just the database file were deleted. Deleting the App's data would delete the shared preferences so result in the database being copied.
        • 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
          

          • 额外的消息是由于报告数据库没有被复制时使用了更广泛的消息,因此再次调用了添加日志消息的调用方法.
            • Extra messages due the more extensive message used when reporting that the database was not copied calling methods again which add log messages.
            • 这篇关于更新预先填充的数据库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆