Перезапишите существующую поставленную Sqlite DB новой версией DB в моем следующем обновлении приложения для Android - PullRequest
3 голосов
/ 03 июля 2019

Я хотел бы перезаписать существующую БД, которая была поставлена ​​с моей старой версией приложения, с новой полностью заполненной БД в моем следующем обновлении приложения. Однако onUpgrade () никогда не вызывается, хотя я пытался изменить DB_version при передаче его в класс SQLiteOpenHelper.

public class DataBaseHelper extends SQLiteOpenHelper {

    private static Context mContext;
    private static String DB_PATH = "/data/data/<app Package>/databases/";;
    private static final String DBNAME = "DB.db";
    private static DataBaseHelper sInstance;
    private static final int version = 2;


    public static synchronized DataBaseHelper getInstance(Context context) {
        // Use the application context, which will ensure that you
        // don't accidentally leak an Activity's context.
        if (sInstance == null) {
            sInstance = new DataBaseHelper(context.getApplicationContext());
        }
        return sInstance;
    }

    public DataBaseHelper(Context context, String s){
        super(context, DBNAME, null, version);

    }

    private DataBaseHelper(Context context) {
        super(context, DBNAME, null, version);
        mContext = context;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
        } else {
            DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
        }

        new Handler().post(new Runnable() {

            @Override
            public void run() {
                // If u want to Copy Database from Assets.
                try {
                    CopyAndCreateDataBase();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }


    // If database not exists copy it from the assets
    public void CopyAndCreateDataBase() throws IOException {
        boolean mDataBaseExist = checkDataBase();
        if (!mDataBaseExist) {
            this.getReadableDatabase();
            this.getWritableDatabase();
            this.close();
            try {
                // Copy the database from assests
                copyDataBase();
                String mPath = DB_PATH + DBNAME;
            } catch (IOException mIOException) {
                throw new Error("ErrorCopyingDataBase");
            }
        }
         //FOR DB TESTING PURPOSES
        else{
            Log.d("DB STATUS:", "Database Already Exists!!!!!!!!!");
        }
    }


    // Check that the database exists here: /data/data/yourpackage/databases/DatabaseName
    private boolean checkDataBase() {
        File dbFile = new File(DB_PATH + DBNAME);
        // Log.v("dbFile", dbFile + "   "+ dbFile.exists());
        return dbFile.exists();
    }

    // Copy the database from assets
    private void copyDataBase() throws IOException {
        InputStream mInput = mContext.getAssets().open(DBNAME);
        String outFileName = DB_PATH + DBNAME;
        OutputStream mOutput = new FileOutputStream(outFileName);
        byte[] mBuffer = new byte[1024];
        int mLength;
        while ((mLength = mInput.read(mBuffer)) > 0) {
            mOutput.write(mBuffer, 0, mLength);
        }
        Log.d("DB STATUS:", "Daatabase Created ----------------"); //FOR DB TESTING PURPOSES
        mOutput.flush();
        mOutput.close();
        mInput.close();
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        Log.d("Database Versions:", "old:"+i+"\nnew:"+i1);

    }
}

Я пробовал много способов вызвать метод onUpgrade (), например, вызвать getReadableDatabase () и getWritableDatabase (но, к сожалению, это сработало. Я хочу перезаписать выходящую базу данных новой поставкой.

1 Ответ

1 голос
/ 04 июля 2019

Я считаю, что ваша проблема ( первоначальная проблема, пожалуйста, прочитайте весь ответ ), возможно, использует обработчик.Конечно, тестирование доступного кода приводит к непредвиденным результатам (база данных всегда указывается как существующая, поэтому никогда не копирует БД из активов, если база данных никогда не вызывает onUpgrade (я предполагаю, что база данных уже открыта из-задля неявных открытий и, следовательно, не предпринимается никаких попыток выполнить открытую обработку)).

Изменение в использовании: -

    try {
        CopyAndCreateDataBase();
    } catch (IOException e) {
        e.printStackTrace();
    }

    /*
    new Handler().post(new Runnable() {

        @Override
        public void run() {
            // If u want to Copy Database from Assets.
            try {
                CopyAndCreateDataBase();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    });
    */

Создает ожидаемые результаты, например: -

07-04 06:55:38.836 4365-4365/aso.so56873021recopydb D/DBEXISTS: The database /data/user/0/aso.so56873021recopydb/databases/DB.db was found.
07-04 06:55:38.836 4365-4365/aso.so56873021recopydb D/DB STATUS:: Database Already Exists!!!!!!!!!
07-04 06:55:38.838 4365-4365/aso.so56873021recopydb D/Database Versions:: old:1
    new:2
  • Обратите внимание, что сообщение DBEXISTS было добавлено при тестировании кода для выявления проблемы.

В тестировании использовался следующий код в операции: -

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DataBaseHelper mDBHlpr = DataBaseHelper.getInstance(this);
        Cursor csr = mDBHlpr.getWritableDatabase().query("sqlite_master",null,null,null,null,null,null);
        DatabaseUtils.dumpCursor(csr);
    }
}

Часть 2 - Обновление

Короче говоря, есть проблемы в этом, даже если вы можете вызвать onUpgrade , когда версия увеличивается после исправления предыдущей проблемы, как при вызове onUpgrade база данных уже открыта, и копирование новой базы данных будет фактически отменено, поскольку старая база данных перезапишет вновь скопированные базы данных.Таким образом, изменения теряются.

Вместо этого я предлагаю проверять, копировать и перезаписывать базу данных до , чтобы создать экземпляр помощника базы данных, например, в методе getInstance .

Поэтому я бы предложил следующий помощник по базам данных (см. Комментарии о внесенных изменениях): -

public class DataBaseHelper extends SQLiteOpenHelper {

    private static Context mContext;
    //private static String DB_PATH = "/data/data/<app Package>/databases/"; //NOT NEEDED Contexts getDatabasePath used instead
    private static final String DBNAME = "DB.db";
    private static DataBaseHelper sInstance;
    private static final int version = 2;


    public static synchronized DataBaseHelper getInstance(Context context) {
        // Use the application context, which will ensure that you
        // don't accidentally leak an Activity's context.
        checkDB(context.getApplicationContext(),DBNAME,version); //<<<<<<<<<< do the stuff before DatabaseHelper instantiation
        if (sInstance == null) {
            sInstance = new DataBaseHelper(context.getApplicationContext());
        }
        return sInstance;
    }

    private DataBaseHelper(Context context) {
        super(context, DBNAME, null, version);
        mContext = context;
    }

    // Copy the database from assets
    //<<<<<<<<<< CHANGED TO USE getDatabasepath requiring Context to be passed
    private static void copyDataBase(Context context) throws IOException {
        InputStream mInput = context.getAssets().open(DBNAME);
        String outFileName = context.getDatabasePath(DBNAME).toString();
        OutputStream mOutput = new FileOutputStream(outFileName);
        Log.d("DBCOPY","DB Copy inititaed"); //<<<<<<<<<< ADDED FOR TESTING
        byte[] mBuffer = new byte[1024];
        int mLength;
        int bytescopied = 0;
        while ((mLength = mInput.read(mBuffer)) > 0) {
            mOutput.write(mBuffer, 0, mLength);
            bytescopied = bytescopied + mLength;
        }
        Log.d("DBCOPY", "Database copied. " + String.valueOf(bytescopied) + " bytes copied." ); //<<<<<<<<<< ADDED FOR TESTING
        Log.d("DB STATUS:", "Daatabase Created ----------------"); //FOR DB TESTING PURPOSES
        mOutput.flush();
        mOutput.close();
        mInput.close();
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        //<<<<<<<<<< ONLY USE ME FOR SCHEMA CHANGES !!!!NOT!!!! new DB copy
        Log.d("Database Versions:", "old:"+i+"\nnew:"+i1);
    }

    //<<<<<<<<<< NEW 
    private static void checkDB(Context context, String dbname, int version) {
        int dbversion;
        // Note uses the Contexts getDatabasePath
        File dbfile = new File(context.getDatabasePath(dbname).toString());
        if (!dbfile.exists()) {
            //<<<<<<<<<< create the databases directory (or whatever it is the future)
            if (!dbfile.getParentFile().exists()) {
                dbfile.getParentFile().mkdirs();
            }
            //<<<<<<<<<< Now do the copy of the initial DB 
            //<<<<<<<<<< Note new install will copy the latest DB
            try {
                copyDataBase(context);
            } catch (IOException e) {
                e.printStackTrace();
                throw new Error("Error copying initial Database.");
            }
        } 

        // If the database file does exist then retrieve the version
        else {


            SQLiteDatabase db = SQLiteDatabase.openDatabase(context.getDatabasePath(dbname).toString(),null,SQLiteDatabase.OPEN_READWRITE);
            dbversion = db.getVersion();
            Log.d("DBVERSION","The stored database version is " + String.valueOf(dbversion));
            db.close();

            //<<<<<<<<<< if the database's version is less than the coded version then copy the DB
            //<<<<<<<<<< NOTE!!!! always assumes new version = new copy
            //<<<<<<<<<< IF NOt WANTED THEN DO SPECIFIC VERSION CHECKING 
            if (dbversion <  version) {

                //<<<<<<<<<<<< EXAMPLE skip copy on version 10 >>>>>>>>>>
                //<TODO> Remove example check if not needed
                if (dbversion < version && version == 10) {
                    return;
                }
                //<<<<<<<<<< For Android 9+ delete the -wal and -shm files if copying database
                if (new File(context.getDatabasePath(dbname).toString() + "-wal").exists()) {
                    new File(context.getDatabasePath(dbname).toString() + "-wal").delete();
                }
                if (new File(context.getDatabasePath(dbname).toString() + "-shm").exists()) {
                    new File(context.getDatabasePath(dbname).toString() + "-shm").delete();
                }
                try {
                    copyDataBase(context);
                } catch (IOException e) {
                    e.printStackTrace();
                    throw new Error("Error copying upgraded database");
                }
            }
        }
    }
}

Тестирование

Выше было протестировано.Тестирование было основано на двух базах данных (совершенно разных) с использованием следующего в задании: -

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DataBaseHelper mDBHlpr = DataBaseHelper.getInstance(this);
        Cursor csr = mDBHlpr.getWritableDatabase().query("sqlite_master",null,null,null,null,null,null);
        DatabaseUtils.dumpCursor(csr);
    }
}

Ниже приведена папка ресурсов: -

enter image description here

  • Исходная база данных OLDDB.db скопирована в DB.db.Последующей новой базой данных будет NEWDB.db.

Тестирование проводилось на двух устройствах API 23 и API 28 (Oreo so Pie + и WAL).

Этап 1

Сначала приложение было запущено с файлами, как указано выше, и версией была установлена ​​ 1 .В результате получается журнал, содержащий: -

07-04 10:20:32.120 8154-8154/aso.so56873021recopydb D/DBCOPY: DB Copy inititaed
07-04 10:20:32.120 8154-8154/aso.so56873021recopydb D/DBCOPY: Database copied. 36864 bytes copied.
07-04 10:20:32.120 8154-8154/aso.so56873021recopydb D/DB STATUS:: Daatabase Created ----------------
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@6e2c433
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: 0 {
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out:    type=table
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out:    name=android_metadata
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out:    tbl_name=android_metadata
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out:    rootpage=3
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out:    sql=CREATE TABLE android_metadata (locale TEXT)
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: }
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: 1 {
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out:    type=table
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out:    name=room_master_table
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out:    tbl_name=room_master_table
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out:    rootpage=4
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out:    sql=CREATE TABLE room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: }
..........
  • 36K скопированных
  • Таблица примечаний room_master_table

Аналогичный результат для API 28устройство: -

2019-07-04 10:22:33.082 4532-4532/aso.so56873021recopydb D/DBCOPY: DB Copy inititaed
2019-07-04 10:22:33.083 4532-4532/aso.so56873021recopydb D/DBCOPY: Database copied. 36864 bytes copied.
2019-07-04 10:22:33.083 4532-4532/aso.so56873021recopydb D/DB STATUS:: Daatabase Created ----------------
2019-07-04 10:22:33.088 4532-4532/aso.so56873021recopydb I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@2f7f7bc
2019-07-04 10:22:33.089 4532-4532/aso.so56873021recopydb I/System.out: 0 {

Этап 2

Приложение было запущено снова без изменений результатов (т. е. без копии БД): -

07-04 10:24:13.642 8244-8244/? D/DBVERSION: The stored database version is 1
07-04 10:24:13.644 8244-8244/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@8c743f0

и на устройстве API 28:-

2019-07-04 10:26:24.531 4620-4620/? D/DBVERSION: The stored database version is 1
2019-07-04 10:26:24.536 4620-4620/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@877f345

Этап 3

Файлы в папке ресурсов изменены на: -

enter image description here

Повторный запуск приложения БЕЗ изменения версии : -

Нет Копирование и исходные данные: -

07-04 10:30:01.838 8369-8369/? D/DBVERSION: The stored database version is 1
07-04 10:30:01.840 8369-8369/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@8c743f0
07-04 10:30:01.840 8369-8369/? I/System.out: 0 {
07-04 10:30:01.840 8369-8369/? I/System.out:    type=table
07-04 10:30:01.840 8369-8369/? I/System.out:    name=android_metadata
07-04 10:30:01.840 8369-8369/? I/System.out:    tbl_name=android_metadata
07-04 10:30:01.840 8369-8369/? I/System.out:    rootpage=3
07-04 10:30:01.840 8369-8369/? I/System.out:    sql=CREATE TABLE android_metadata (locale TEXT)
07-04 10:30:01.840 8369-8369/? I/System.out: }
07-04 10:30:01.840 8369-8369/? I/System.out: 1 {
07-04 10:30:01.840 8369-8369/? I/System.out:    type=table
07-04 10:30:01.840 8369-8369/? I/System.out:    name=room_master_table

и по API 28: -

2019-07-04 10:31:11.591 4757-4757/aso.so56873021recopydb D/DBVERSION: The stored database version is 1
2019-07-04 10:31:11.596 4757-4757/aso.so56873021recopydb I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@877f345
2019-07-04 10:31:11.596 4757-4757/aso.so56873021recopydb I/System.out: 0 {
2019-07-04 10:31:11.596 4757-4757/aso.so56873021recopydb I/System.out:    type=table
2019-07-04 10:31:11.596 4757-4757/aso.so56873021recopydb I/System.out:    name=android_metadata
2019-07-04 10:31:11.596 4757-4757/aso.so56873021recopydb I/System.out:    tbl_name=android_metadata
2019-07-04 10:31:11.597 4757-4757/aso.so56873021recopydb I/System.out:    rootpage=3
2019-07-04 10:31:11.597 4757-4757/aso.so56873021recopydb I/System.out:    sql=CREATE TABLE android_metadata (locale TEXT)
2019-07-04 10:31:11.597 4757-4757/aso.so56873021recopydb I/System.out: }
2019-07-04 10:31:11.597 4757-4757/aso.so56873021recopydb I/System.out: 1 {
2019-07-04 10:31:11.597 4757-4757/aso.so56873021recopydb I/System.out:    type=table
2019-07-04 10:31:11.597 4757-4757/aso.so56873021recopydb I/System.out:    name=room_master_table

Этап 4

version increased from 1 to 2 :-

07-04 10:38:42.679 8857-8857/? D/DBVERSION: The stored database version is 1
07-04 10:38:42.679 8857-8857/? D/DBCOPY: DB Copy inititaed
07-04 10:38:42.680 8857-8857/? D/DBCOPY: Database copied. 77824 bytes copied.
07-04 10:38:42.680 8857-8857/? D/DB STATUS:: Daatabase Created ----------------
07-04 10:38:42.683 8857-8857/? D/Database Versions:: old:1
    new:2
07-04 10:38:42.688 8857-8857/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@f2b3d69
07-04 10:38:42.688 8857-8857/? I/System.out: 0 {
07-04 10:38:42.688 8857-8857/? I/System.out:    type=table
07-04 10:38:42.688 8857-8857/? I/System.out:    name=android_metadata
07-04 10:38:42.688 8857-8857/? I/System.out:    tbl_name=android_metadata
07-04 10:38:42.688 8857-8857/? I/System.out:    rootpage=3
07-04 10:38:42.689 8857-8857/? I/System.out:    sql=CREATE TABLE android_metadata (locale TEXT)
07-04 10:38:42.689 8857-8857/? I/System.out: }
07-04 10:38:42.689 8857-8857/? I/System.out: 1 {
07-04 10:38:42.689 8857-8857/? I/System.out:    type=table
07-04 10:38:42.689 8857-8857/? I/System.out:    name=shops
07-04 10:38:42.689 8857-8857/? I/System.out:    tbl_name=shops
07-04 10:38:42.689 8857-8857/? I/System.out:    rootpage=4
07-04 10:38:42.689 8857-8857/? I/System.out:    sql=CREATE TABLE shops (_id INTEGER  PRIMARY KEY , shoporder INTEGER  DEFAULT 1000 , shopname TEXT , shopstreet TEXT , shopcity TEXT , shopstate TEXT , shopnotes TEXT )
07-04 10:38:42.689 8857-8857/? I/System.out: }
........
  • Примечание 76K скопировано и таблица теперь в магазинах

А по API 28: -

2019-07-04 10:40:31.799 5010-5010/aso.so56873021recopydb D/DBVERSION: The stored database version is 1
2019-07-04 10:40:31.800 5010-5010/aso.so56873021recopydb D/DBCOPY: DB Copy inititaed
2019-07-04 10:40:31.802 5010-5010/aso.so56873021recopydb D/DBCOPY: Database copied. 77824 bytes copied.
2019-07-04 10:40:31.802 5010-5010/aso.so56873021recopydb D/DB STATUS:: Daatabase Created ----------------
2019-07-04 10:40:31.826 5010-5010/aso.so56873021recopydb D/Database Versions:: old:1
    new:2
...........

Этап 5

Приложение запускается снова (т.е. пост-копия уже сделана): -

07-04 10:41:53.653 8947-8947/? D/DBVERSION: The stored database version is 2
07-04 10:41:53.655 8947-8947/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@8c743f0
07-04 10:41:53.655 8947-8947/? I/System.out: 0 {
07-04 10:41:53.655 8947-8947/? I/System.out:    type=table
07-04 10:41:53.655 8947-8947/? I/System.out:    name=android_metadata
07-04 10:41:53.655 8947-8947/? I/System.out:    tbl_name=android_metadata
07-04 10:41:53.655 8947-8947/? I/System.out:    rootpage=3
07-04 10:41:53.655 8947-8947/? I/System.out:    sql=CREATE TABLE android_metadata (locale TEXT)
07-04 10:41:53.655 8947-8947/? I/System.out: }
07-04 10:41:53.655 8947-8947/? I/System.out: 1 {
07-04 10:41:53.655 8947-8947/? I/System.out:    type=table
07-04 10:41:53.655 8947-8947/? I/System.out:    name=shops
07-04 10:41:53.655 8947-8947/? I/System.out:    tbl_name=shops

И по API 28: -

2019-07-04 10:42:41.296 5098-5098/aso.so56873021recopydb D/DBVERSION: The stored database version is 2
2019-07-04 10:42:41.306 5098-5098/aso.so56873021recopydb I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@877f345
2019-07-04 10:42:41.307 5098-5098/aso.so56873021recopydb I/System.out: 0 {
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out:    type=table
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out:    name=android_metadata
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out:    tbl_name=android_metadata
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out:    rootpage=3
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out:    sql=CREATE TABLE android_metadata (locale TEXT)
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out: }
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out: 1 {
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out:    type=table
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out:    name=shops
2019-07-04 10:42:41.309 5098-5098/aso.so56873021recopydb I/System.out:    tbl_name=shops
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...