Как прочитать номер версии из файла базы данных в Android, который находится в папке активов - PullRequest
0 голосов
/ 18 февраля 2019

У меня есть файл SQLite в папке активов в базе данных пакетов, который я помещаю вручную (например: src -> main-> asset-> database-> q-db (q-db - мой файл SQLite).

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

Я много гуглил, но не смог получить номер версии файла, то, что я получаю, это мой номер версии SQLite, который яне хочу в моем случае. Ваша любезная поддержка будет высоко оценена.

Для справки: Я следую аналогично этому:

https://www.concretepage.com/android/android-ship-sqlite-database-with-apk-copy-sqlite-database-from-assets-folder-to-data-example

1 Ответ

0 голосов
/ 18 февраля 2019

Не существует единого номера версии, вместо этого номер версии может иметь несколько значений.

Предполагается, что вы говорите о user_version , который использует Android SDK SQLiteOpenHelper.

Существует также application_id , который, например, user_version, может использоваться в качестве пользовательской переменной.

Вы уже встретили SQLite_Version, поэтому его можно сбрасывать со счетов.

Существует также data_version, вряд ли это будет номер версии, так как он предназначен для использования в качестве индикации, если файл базы данных был изменен в реальном времени.

Существует также схема_версии,вы, вероятно, НЕ хотите использовать это как Предупреждение. Неправильное использование этой прагмы может привести к повреждению базы данных.

user_version

Как вы уже сказали ранеевероятно, речь идет о user_version .Первое, что нужно отметить, это то, что это контролируемая пользователем переменная / поле, доступное для пользовательского использования.SQlite не использует и не изменяет user_version , но позволяет изменять и использовать его.

Более того, менеджеры SQLite (такие как DB Browser, Navicat и т. Д.) Не будут автоматически изменять номер версии.Таким образом, вам нужно было бы намеренно изменить user_version, чтобы он был доступен, прежде чем копировать файл базы данных в папку активов (при этом следует учитывать, что при этом вы используете подкласс SQLiteOpenHelper, что onUpgrade и onDowngrade методы могут быть вызваны).

Если user_version специально не изменена и к базе данных обращался только с помощью инструмента SQLite Manager, тогда ее user_version будет 0. Если файл базы данных был открыт путем копирования файла базы данных изAndroid-приложение, которое использует подкласс SQLiteOpenHelper, и оно будет иметь user_version 1 или более (в зависимости от последнего значения, использованного в качестве 4-го параметра для constrcutor SQLiteOpenHelper).Конечно, если user_version изменяется программно, то такое изменение также будет отражено, если файл будет скопирован в инструмент SQlite Manager.

Перед копированием файла user_version обычно изменяется в инструменте SQlite Manager насоответствующее значение.

Вы можете изменить user_version , используя SQL PRAGMA user_version = 5;. Вы можете получить user_version , используя PRAGMA user_version или SELECT * FROM pragma_user_version;

Если вам нужно проверить версию перед открытием базы данных, то вы можете прочитать 4 байта со смещением 60 и преобразовать 4 байта в целое число, чтобы сравнить user_version с другим значением.В противном случае вам, вероятно, придется скопировать файл, вероятно, с другим именем, из папки ресурсов, открыть его как базу данных SQLite и получить версию user_version с использованием приведенного выше SQL-кода, а затем сравнить его с другим значением, закрыв файл базы данных.Удаление файла, если не нужно, в противном случае удалить предыдущий файл базы данных, а затем переименовать скопированный файл.

Пример

Ниже приведен рабочий пример (обратите внимание, что я редко использую Kotlin, и это имеетбыл преобразован с использованием AS studio из java).

Используется класс, а именно SQLAssetVersionCheck , который извлекает номер версии из файла, а не открывает файл как базу данных SQLite.

SQLAssetVersionCheck.kt: -

class SQLAssetVersionCheck
/**
 * Full SQLAssetVersionCheck Constructor - sub directories can be specified
 * @param context           Assets are part of package so use the context to get the asset file
 * @param dbName            The database name (i.e. the file name)
 * @param subDirectories    The sub-directories as per the heirarchial order
 * @param dbVersion         The database version to check against
 */
(context: Context, val databaseName: String, subDirectories: Array<String>?, dbVersion: Int) {
    val assetPath: String
    var databaseVersion: Int = 0
        private set
    var result: Int = 0
        private set


    init {
        assetPath = applySubDirectories(databaseName, subDirectories)
        Log.d("SQLAVC", "Looking for Asset $assetPath")
        var stage = 0
        try {
            val `is` = context.assets.open(assetPath)
            stage++
            // Get the first 64 bytes of the header
            val v = ByteArray(64)
            `is`.read(v, 0, 64)
            // only interested in the 4 bytes from offset 60 so get them
            val v2 = ByteArray(4)
            for (i in 60..63) {
                v2[i - 60] = v[i]
            }
            stage++
            // Done with the InputStream so close it
            `is`.close()
            // Extarct the stored DBVersion
            databaseVersion = ByteBuffer.wrap(v2).int
            if (databaseVersion < dbVersion) {
                result = ASSETVERSIONLOW

            }
            if (databaseVersion > dbVersion) {
                result = ASSETVERSIONHIGH
            }
            if (databaseVersion == dbVersion) {
                result = ASSETVERSIONMATCH
            }

        } catch (e: IOException) {
            e.printStackTrace()
            when (stage) {
                0 -> result = ASSETNOTFOUND
                1 -> result = ASSETIOERROR
            }
        }

    }

    constructor(context: Context, dbName: String, dbVersion: Int) : this(context, dbName, null, dbVersion) {}

    private fun applySubDirectories(dbname: String, subDirectories: Array<String>?): String {
        val base = StringBuffer("")
        var firstdirectory = true
        if (subDirectories != null) {
            for (d in subDirectories) {
                if (!firstdirectory) {
                    base.append(File.separatorChar)
                }
                firstdirectory = false
                base.append(d)
            }
        }
        if (base.length > 0) {
            base.append(File.separatorChar)
        }
        base.append(dbname)
        return base.toString()
    }

    companion object {

        val ASSETNOTFOUND = -2
        val ASSETIOERROR = -3
        val ASSETVERSIONMATCH = 0
        val ASSETVERSIONHIGH = 1
        val ASSETVERSIONLOW = -1
    }
}

А вот действие, которое дважды использует вышеуказанный класс, чтобы попытаться проверить версию в файле testdb .

  • Первое использование не находит файл базы данных testdb , так как он ищет в папке assets (не подкаталог базы данных).

  • Второе использование находит файл testdb в качестве подкаталога database (третий параметр полного конструктора), находя в assets / database/ папка, т.е. assets / database / testdb : -

MainActivity.kt: -

class MainActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val db_version_to_check_against = 100

        var mAVC1 = SQLAssetVersionCheck(this, "testdb", 100)

        var result = ""
        when (mAVC1.result) {
            SQLAssetVersionCheck.ASSETIOERROR -> result = "IO ERROR detected - check the Log"
            SQLAssetVersionCheck.ASSETNOTFOUND -> result = "The Asset, for Database " + mAVC1.databaseName + " was not located at  " + mAVC1.assetPath
            SQLAssetVersionCheck.ASSETVERSIONHIGH -> result = "The Asset was located and the version number being " +
                    mAVC1.databaseVersion.toString() +
                    " was higher than the version to be checked which was " +
                    db_version_to_check_against.toString()
            SQLAssetVersionCheck.ASSETVERSIONLOW -> result = "The Asset was located and the version number being " +
                    mAVC1.databaseVersion.toString() +
                    " was lower than the version to be checked which was " +
                    db_version_to_check_against.toString()
            SQLAssetVersionCheck.ASSETVERSIONMATCH -> result = "The Asset version and the version to be check ed are the same."
        }
        Log.d("ASSETVERSIONCHECK", "The result of the version check was - $result")

        var mAVC2 = SQLAssetVersionCheck(this, "testdb", arrayOf("databases"), db_version_to_check_against)
        result = ""
        when (mAVC2.result) {
            SQLAssetVersionCheck.ASSETIOERROR -> result = "IO ERROR detected - check the Log"
            SQLAssetVersionCheck.ASSETNOTFOUND -> result = "The Asset, for Database " + mAVC2.databaseName + " was not located at  " + mAVC2.assetPath
            SQLAssetVersionCheck.ASSETVERSIONHIGH -> result = "The Asset was located and the version number being " +
                    mAVC2.databaseVersion.toString() +
                    " was higher than the version to be checked which was " +
                    db_version_to_check_against.toString()
            SQLAssetVersionCheck.ASSETVERSIONLOW -> result = "The Asset was located and the version number being " +
                    mAVC2.databaseVersion.toString() +
                    " was lower than the version to be checked which was " +
                    db_version_to_check_against.toString()
            SQLAssetVersionCheck.ASSETVERSIONMATCH -> result = "The Asset version and the version to be check ed are the same."
        }
        Log.d("ASSETVERSIONCHECK", "The result of the version check was - $result")
    }
}

Результат (журнал): -

2019-02-19 13:11:34.473 19058-19058/com.example.so54741423assetdbversioning D/SQLAVC: Looking for Asset testdb
2019-02-19 13:11:34.473 19058-19058/com.example.so54741423assetdbversioning W/System.err: java.io.FileNotFoundException: testdb
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.content.res.AssetManager.nativeOpenAsset(Native Method)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.content.res.AssetManager.open(AssetManager.java:744)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.content.res.AssetManager.open(AssetManager.java:721)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at com.example.so54741423assetdbversioning.SQLAssetVersionCheck.<init>(SQLAssetVersionCheck.kt:31)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at com.example.so54741423assetdbversioning.SQLAssetVersionCheck.<init>(SQLAssetVersionCheck.kt:67)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at com.example.so54741423assetdbversioning.MainActivity.onCreate(MainActivity.kt:17)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.Activity.performCreate(Activity.java:7136)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.Activity.performCreate(Activity.java:7127)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:106)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.os.Looper.loop(Looper.java:193)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6669)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning D/ASSETVERSIONCHECK: The result of the version check was - The Asset, for Database testdb was not located at  testdb




2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning D/SQLAVC: Looking for Asset databases/testdb
2019-02-19 13:11:34.477 19058-19058/com.example.so54741423assetdbversioning D/ASSETVERSIONCHECK: The result of the version check was - The Asset was located and the version number being 5 was lower than the version to be checked which was 100
  • Первая попытка не находит файл (отображается исключение, которое было перехвачено) и отображает строку Результатом проверки версии было - Актив, для базы данных testdb не был расположен в testdb, которое будет отображаться.

  • Вторая попытка работает и приводит к Результат проверки версии был следующим: - Актив был найден, а номер версии 5 был меньше, чемверсия для проверки, которая была 100

  • Добавлен пробел строк, чтобы отделить вторую попытку от первой.

Дополнительно

После использования инструмента SQLite Manager (Navicat) и использования: -

PRAGMA user_version = 101;

Затем копирование файла (после закрытия подключения в Navicat) в папку ресурсов (поэтому у меня естьдва файла testdb), тогда результат: -

2019-02-19 13:50:09.874 19253-19253/com.example.so54741423assetdbversioning D/SQLAVC: Looking for Asset testdb
2019-02-19 13:50:09.874 19253-19253/com.example.so54741423assetdbversioning D/ASSETVERSIONCHECK: The result of the version check was - The Asset was located and the version number being 101 was higher than the version to be checked which was 100
2019-02-19 13:50:09.874 19253-19253/com.example.so54741423assetdbversioning D/SQLAVC: Looking for Asset databases/testdb
2019-02-19 13:50:09.874 19253-19253/com.example.so54741423assetdbversioning D/ASSETVERSIONCHECK: The result of the version check was - The Asset was located and the version number being 5 was lower than the version to be checked which was 100
  • т.е. новый файл имеет user_version как 101 и поэтому первый находит файл, второй находит файл (user_version 5), как раньше.
...