资产文件夹中的 DB 文件.会更新吗? [英] DB File in Assets Folder. Will it be Updated?

查看:41
本文介绍了资产文件夹中的 DB 文件.会更新吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 Android SQLite 的新手.这就是我所拥有的:

I'm new to the Android SQLite whole thing. This is what I have:

  • 我的 assets 文件夹中有 db.sqlite.
  • 数据库的目的是只读.用户不会写信给它.
  • 当应用更新时,db.sqlite 将被替换为一个新的 db(我将从项目中删除旧文件并添加新文件).
  • I have db.sqlite in my assets folder.
  • The intent of the db is to READ ONLY. The user will not write to it.
  • When the app gets updated, the db.sqlite will be replaced be a new db (I'll delete the old file from the project and add the new one).

我担心的是:

  • 旧的 db 文件会被删除吗?(这就是我想要的;用新的替换旧的)
    • 为什么要问?因为当我调试我的应用程序时,每次更新db文件时,我都需要从设备上卸载应用程序才能强制更新.当用户从 Play 商店更新我的应用程序时,他们是否需要做同样的事情?我很害怕.
    • 如果是,实施它们以满足我的要求的正确方法是什么?

    这就是我扩展 SQLiteOpenHelper 类的方式.我遵循了在互联网上找到的教程:

    This is how I extends the SQLiteOpenHelper class. I followed a tutorial I found in the internet:

    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;    
    import android.content.Context;
    import android.database.Cursor;
    import android.database.SQLException;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteException;
    import android.database.sqlite.SQLiteOpenHelper;
    import android.util.Log;
    
    public class DataBaseHelper extends SQLiteOpenHelper{
    
        //The Android's default system path of your application database.
        private static String DB_PATH = "/data/data/com.mydomain.myapp/databases/";
        private static String DB_NAME = "db.sqlite";
        private SQLiteDatabase myDataBase;   
        private final Context myContext;
    
        /*
         * Constructor
         * Takes and keeps a reference of the passed context in order to access to the application assets and resources.
         * @param context
         **/
        public DataBaseHelper(Context context) {
    
            super(context, DB_NAME, null, 1);
            this.myContext = context;
        }   
    
      /**
         * Creates a empty database on the system and rewrites it with your own database.
         * */
        public void createDataBase() throws IOException{
    
            boolean dbExist = checkDataBase();
    
            if(dbExist){
                //do nothing - database already exist
                Log.i("myapp", "database already exist");
            }else{
                Log.i("myapp", "database NOT exist");
    
                //By calling this method and empty database will be created into the default system path
                   //of your application so we are gonna be able to overwrite that database with our database.
                this.getReadableDatabase();
    
                try {
    
                    copyDataBase();
    
                } catch (IOException e) {
    
                    throw new Error("Error copying database");
    
                }
            }
    
        }
    
        /**
         * Check if the database already exist to avoid re-copying the file each time you open the application.
         * @return true if it exists, false if it doesn't
         */
        private boolean checkDataBase(){
    
            SQLiteDatabase checkDB = null;
    
            try{
                String myPath = DB_PATH + DB_NAME;
                checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
    
            }catch(SQLiteException e){
    
                //database does't exist yet.
    
            }
    
            if(checkDB != null){
    
                checkDB.close();
    
            }
    
            return checkDB != null ? true : false;
        }
    
        /**
         * Copies your database from your local assets-folder to the just created empty database in the
         * system folder, from where it can be accessed and handled.
         * This is done by transfering bytestream.
         * */
        private void copyDataBase() throws IOException{
    
            //Open your local db as the input stream
            InputStream myInput = myContext.getAssets().open(DB_NAME);
    
            // Path to the just created empty db
            String outFileName = DB_PATH + DB_NAME;
    
            //Open the empty db as the output stream
            OutputStream myOutput = new FileOutputStream(outFileName);
    
            //transfer bytes from the inputfile to the outputfile
            byte[] buffer = new byte[1024];
            int length;
            while ((length = myInput.read(buffer))>0){
                myOutput.write(buffer, 0, length);
            }
    
            //Close the streams
            myOutput.flush();
            myOutput.close();
            myInput.close();
    
        }
    
        public void openDataBase() throws SQLException{
    
            //Open the database
            String myPath = DB_PATH + DB_NAME;
            myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
    
        }
    
        @Override
        public synchronized void close() {
    
                if(myDataBase != null)
                    myDataBase.close();
    
                super.close();
    
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
    
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    
        }
    
      // My public helper methods to access and get content from the database go here
    

    推荐答案

    您不能在 onUpgrade() 中替换数据库,因为在此方法中数据库已在使用中.您必须在打开数据库之前执行此操作,就像在 DatabaseHelper 的构造函数中一样.由于您不能使用 onUpgrade(),您必须自己管理数据库版本控制.使用 SharedPreferences 是一个很好的方法.您检查您的数据库是否存在(如果它已经从 assets 目录复制)并检查版本是否存在数据库.现在您可以删除旧数据库并从 assets 复制新数据库.请参阅下面的实现.

    You can't replace database in onUpgrade() because in this method the database is already in use. You have to do it before the database is open, like in a constructor of your DatabaseHelper. As you can't use onUpgrade(), you have to manage database versioning by yourself. Using SharedPreferences is a good way for it. You check if your database exists (if it is already copied from assets directory) and check the version if database exists. Now you can delete old database and copy new one from assets. See implementation below.

    为了标记您更新的应用程序是在 assets 中使用新数据库发布的,只需增加 DATABASE_VERSION 常量.

    To mark your updated application is published with new database in assets just incerment DATABASE_VERSION constant.

    private static class DatabaseHelper extends SQLiteOpenHelper {
    
        private static final String DATABASE_NAME = "database.db";
        private static final int DATABASE_VERSION = 1;
        private static final String SP_KEY_DB_VER = "db_ver";
        private final Context mContext;
    
        public DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
            mContext = context;
            initialize();
        }
    
        /**
         * Initializes database. Creates database if doesn't exist.
         */
        private void initialize() {
            if (databaseExists()) {
                SharedPreferences prefs = PreferenceManager
                        .getDefaultSharedPreferences(mContext);
                int dbVersion = prefs.getInt(SP_KEY_DB_VER, 1);
                if (DATABASE_VERSION != dbVersion) {
                    File dbFile = mContext.getDatabasePath(DATABASE_NAME);
                    if (!dbFile.delete()) {
                        Log.w(TAG, "Unable to update database");
                    }
                }
            }
            if (!databaseExists()) {
                createDatabase();
            }
        }
    
        /**
         * Returns true if database file exists, false otherwise.
         * @return
         */
        private boolean databaseExists() {
            File dbFile = mContext.getDatabasePath(DATABASE_NAME);
            return dbFile.exists();
        }
    
        /**
         * Creates database by copying it from assets directory.
         */
        private void createDatabase() {
            String parentPath = mContext.getDatabasePath(DATABASE_NAME).getParent();
            String path = mContext.getDatabasePath(DATABASE_NAME).getPath();
    
            File file = new File(parentPath);
            if (!file.exists()) {
                if (!file.mkdir()) {
                    Log.w(TAG, "Unable to create database directory");
                    return;
                }
            }
    
            InputStream is = null;
            OutputStream os = null;
            try {
                is = mContext.getAssets().open(DATABASE_NAME);
                os = new FileOutputStream(path);
    
                byte[] buffer = new byte[1024];
                int length;
                while ((length = is.read(buffer)) > 0) {
                    os.write(buffer, 0, length);
                }
                os.flush();
                SharedPreferences prefs = PreferenceManager
                        .getDefaultSharedPreferences(mContext);
                SharedPreferences.Editor editor = prefs.edit();
                editor.putInt(SP_KEY_DB_VER, DATABASE_VERSION);
                editor.commit();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (os != null) {
                    try {
                        os.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion,
                int newVersion) {
        }
    }
    

    这篇关于资产文件夹中的 DB 文件.会更新吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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